blob: 7c49e2311b378b5eb300bf6c889517a60e919fd8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.internal.provisional.tmf.core.model.filter.parser;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.antlr.runtime.tree.CommonTree;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterCompareNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterContainsNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterEqualsNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterMatchesNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterOrNode;
import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterTreeNode;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.filter.parser.FilterParserParser;
import com.google.common.collect.ImmutableList;
/**
* This implements a filter expression compilation unit
*
* @author Jean-Christian Kouame
*
*/
public class FilterExpressionCu implements IFilterCu {
private List<Object> fElements;
/**
* Constructor
*
* @param elements
* The list of elements representing the logical expression
*/
public FilterExpressionCu(List<Object> elements) {
fElements = elements;
}
/**
* Get the list of elements that define this logical expression
*
* @return the list of elements
*/
public List<Object> getElement() {
return fElements;
}
/**
* Compile a filter expression from a tree
*
* @param treeNode
* The root node used to build this compilation unit
* @return a filter expression compilation unit
*/
public static @Nullable FilterExpressionCu compile(CommonTree treeNode) {
int childCount = treeNode.getChildCount();
// We can only have an odd number of parameter at this point
if (childCount % 2 != 1) {
return null;
}
List<Object> elements = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
if (i % 2 == 0) {
CommonTree nodeTree = (CommonTree) treeNode.getChild(i);
int subChildCount = nodeTree.getChildCount();
if (nodeTree.getType() == FilterParserParser.ROOT1) {
boolean negate = nodeTree.getChild(0).getText().equals(IFilterStrings.NOT);
// The logical part is the penultimate child
CommonTree logical = Objects.requireNonNull((CommonTree) nodeTree.getChild(subChildCount - 2));
FilterExpressionCu cu = negate ? FilterExpressionNotCu.compile(logical) : FilterExpressionCu.compile(logical);
if (cu == null) {
return null;
}
elements.add(cu);
} else if (nodeTree.getType() == FilterParserParser.ROOT2) {
FilterSimpleExpressionCu node = FilterSimpleExpressionCu.compile(nodeTree);
if (node == null) {
return null;
}
elements.add(node);
}
} else {
CommonTree opTree = (CommonTree) treeNode.getChild(i);
String op = opTree.getText();
elements.add(Objects.requireNonNull(op));
}
}
return new FilterExpressionCu(elements);
}
/**
* Generate a filter expression runtime object
*
* @return a filter expression
*/
public FilterExpression generate() {
List<Object> queue = getElementsQueue();
return new FilterExpression(queue);
}
/**
* get the queue of operations this expression validation will do
*
* @return The queue of operation
*/
protected final List<Object> getElementsQueue() {
ImmutableList.Builder<Object> builder = ImmutableList.builder();
int count = fElements.size();
for (int i = 0; i < count; i++) {
if (i % 2 == 0) {
Object element = fElements.get(i);
if (element instanceof FilterSimpleExpressionCu) {
FilterSimpleExpression node = ((FilterSimpleExpressionCu) element).generate();
builder.add(node);
} else if (element instanceof FilterExpressionCu) {
FilterExpression node = ((FilterExpressionCu) element).generate();
builder.add(node);
} else {
throw new IllegalStateException("Unknown element while getting the filter element queue"); //$NON-NLS-1$
}
} else {
Object op = fElements.get(i);
if (!(op instanceof String)) {
throw new IllegalStateException("Element at position " + i + " should be a String"); //$NON-NLS-1$ //$NON-NLS-2$
}
builder.add(op);
}
}
return builder.build();
}
@Override
public ITmfFilterTreeNode getEventFilter(ITmfTrace trace) {
int count = fElements.size();
ITmfFilterTreeNode prevNode = null;
String operator = IFilterStrings.OR;
for (int i = 0; i < count; i++) {
if (i % 2 == 0) {
Object element = fElements.get(i);
if (element instanceof IFilterCu) {
ITmfFilterTreeNode node = ((IFilterCu) element).getEventFilter(trace);
prevNode = mergeEventFilters(prevNode, operator, node);
} else {
throw new IllegalStateException("Unknown element while getting the filter element queue"); //$NON-NLS-1$
}
} else {
Object op = fElements.get(i);
if (!(op instanceof String)) {
throw new IllegalStateException("Element at position " + i + " should be a String"); //$NON-NLS-1$ //$NON-NLS-2$
}
operator = (String) op;
}
}
if (prevNode == null) {
throw new NullPointerException("The filter should not be null at this point"); //$NON-NLS-1$
}
if (getNot()) {
setFilterNot(prevNode);
}
return prevNode;
}
private static void setFilterNot(ITmfFilterTreeNode node) {
// TODO: Ideally all those classes would have a common parent class, but
// that would be API breaking
if (node instanceof TmfFilterOrNode) {
((TmfFilterOrNode) node).setNot(true);
}
if (node instanceof TmfFilterAndNode) {
((TmfFilterAndNode) node).setNot(true);
}
if (node instanceof TmfFilterContainsNode) {
((TmfFilterContainsNode) node).setNot(true);
}
if (node instanceof TmfFilterEqualsNode) {
((TmfFilterEqualsNode) node).setNot(true);
}
if (node instanceof TmfFilterCompareNode) {
((TmfFilterCompareNode) node).setNot(true);
}
if (node instanceof TmfFilterMatchesNode) {
((TmfFilterMatchesNode) node).setNot(true);
}
}
private ITmfFilterTreeNode mergeEventFilters(@Nullable ITmfFilterTreeNode prevNode, String operator, ITmfFilterTreeNode node) {
if (prevNode == null) {
return node;
}
TmfFilterTreeNode parentNode;
if (operator == IFilterStrings.OR) {
TmfFilterOrNode orNode = new TmfFilterOrNode(null);
orNode.setNot(getNot());
parentNode = orNode;
} else {
TmfFilterAndNode andNode = new TmfFilterAndNode(null);
andNode.setNot(getNot());
parentNode = andNode;
}
parentNode.addChild(prevNode);
parentNode.addChild(node);
return parentNode;
}
/**
* Get whether this Cu expression is a negation
*
* @return <code>true</code> if the expression is a negation
*/
protected boolean getNot() {
return false;
}
}