/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.dsl.processor.expression;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
public abstract class DSLExpression {
private TypeMirror resolvedTargetType;
private DSLExpression() {
}
public static DSLExpression parse(String input) {
return Parser.parse(input);
}
public final Set<VariableElement> findBoundVariableElements() {
final Set<VariableElement> variables = new HashSet<>();
this.accept(new AbstractDSLExpressionVisitor() {
@Override
public void visitVariable(Variable variable) {
if (variable.getReceiver() == null) {
variables.add(variable.getResolvedVariable());
}
}
});
return variables;
}
public final Set<Variable> findBoundVariables() {
final Set<Variable> variables = new HashSet<>();
this.accept(new AbstractDSLExpressionVisitor() {
@Override
public void visitVariable(Variable variable) {
if (variable.getReceiver() == null) {
variables.add(variable);
}
}
});
return variables;
}
public Object resolveConstant() {
return null;
}
public boolean containsComparisons() {
final AtomicBoolean found = new AtomicBoolean();
this.accept(new AbstractDSLExpressionVisitor() {
@Override
public void visitBinary(Binary binary) {
if (binary.isComparison()) {
found.set(true);
}
}
});
return found.get();
}
public void setResolvedTargetType(TypeMirror resolvedTargetType) {
this.resolvedTargetType = resolvedTargetType;
}
public TypeMirror getResolvedTargetType() {
return resolvedTargetType;
}
public abstract TypeMirror getResolvedType();
public abstract void accept(DSLExpressionVisitor visitor);
public abstract DSLExpression reduce(DSLExpressionReducer visitor);
private DSLExpression reduceImpl(DSLExpressionReducer reducer) {
DSLExpression expression = reduce(reducer);
if (expression == null) {
return this;
}
return expression;
}
public static final class Negate extends DSLExpression {
private final DSLExpression receiver;
public Negate(DSLExpression receiver) {
this.receiver = receiver;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
receiver.accept(visitor);
visitor.visitNegate(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer visitor) {
DSLExpression newReceiver = receiver.reduceImpl(visitor);
DSLExpression negate = this;
if (newReceiver != receiver) {
negate = new Negate(newReceiver);
negate.setResolvedTargetType(getResolvedTargetType());
}
return negate;
}
public DSLExpression getReceiver() {
return receiver;
}
@Override
public Object resolveConstant() {
Object constant = receiver.resolveConstant();
if (constant instanceof Integer) {
return -(int) constant;
}
return super.resolveConstant();
}
@Override
public TypeMirror getResolvedType() {
return receiver.getResolvedType();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Negate) {
return receiver.equals(((Negate) obj).receiver);
}
return false;
}
@Override
public int hashCode() {
return receiver.hashCode();
}
}
public static final class Binary extends DSLExpression {
private final String operator;
private final DSLExpression left;
private final DSLExpression right;
private TypeMirror resolvedType;
public Binary(String operator, DSLExpression left, DSLExpression right) {
this.operator = operator;
this.left = left;
this.right = right;
}
public boolean isComparison() {
return DSLExpressionResolver.COMPARABLE_OPERATORS.contains(operator) || DSLExpressionResolver.IDENTITY_OPERATORS.contains(operator);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Binary) {
Binary other = (Binary) obj;
return operator.equals(other.operator) && left.equals(other.left) && right.equals(other.right);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(operator, left, right);
}
public String getOperator() {
return operator;
}
public DSLExpression getLeft() {
return left;
}
public DSLExpression getRight() {
return right;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
left.accept(visitor);
right.accept(visitor);
visitor.visitBinary(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer reducer) {
DSLExpression newLeft = left.reduceImpl(reducer);
DSLExpression newRight = right.reduceImpl(reducer);
Binary b = this;
if (newLeft != left || newRight != right) {
b = new Binary(getOperator(), newLeft, newRight);
b.setResolvedTargetType(getResolvedTargetType());
b.setResolvedType(getResolvedType());
}
return reducer.visitBinary(b);
}
@Override
public TypeMirror getResolvedType() {
return resolvedType;
}
public void setResolvedType(TypeMirror resolvedType) {
this.resolvedType = resolvedType;
}
@Override
public String toString() {
return "Binary [left=" + left + ", operator=" + operator + ", right=" + right + ", resolvedType=" + resolvedType + "]";
}
}
public static final class Call extends DSLExpression {
private final DSLExpression receiver;
private final String name;
private final List<DSLExpression> parameters;
private ExecutableElement resolvedMethod;
public Call(DSLExpression receiver, String name, List<DSLExpression> parameters) {
this.receiver = receiver;
this.name = name;
this.parameters = parameters;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Call) {
Call other = (Call) obj;
return Objects.equals(receiver, other.receiver) && name.equals(other.name) && parameters.equals(other.parameters);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(receiver, name, parameters);
}
public DSLExpression getReceiver() {
return receiver;
}
public String getName() {
return name;
}
public List<DSLExpression> getParameters() {
return parameters;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
if (receiver != null) {
receiver.accept(visitor);
}
for (DSLExpression parameter : getParameters()) {
parameter.accept(visitor);
}
visitor.visitCall(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer reducer) {
DSLExpression newReceiver = null;
if (receiver != null) {
newReceiver = receiver.reduceImpl(reducer);
}
boolean parameterChanged = false;
List<DSLExpression> newParameters = new ArrayList<>();
for (DSLExpression param : getParameters()) {
DSLExpression newParam = param.reduceImpl(reducer);
if (newParam != param) {
parameterChanged = true;
newParameters.add(newParam);
} else {
newParameters.add(param);
}
}
Call c = this;
if (newReceiver != receiver || parameterChanged) {
c = new Call(newReceiver, getName(), newParameters);
c.setResolvedMethod(getResolvedMethod());
c.setResolvedTargetType(getResolvedTargetType());
}
return reducer.visitCall(c);
}
@Override
public TypeMirror getResolvedType() {
if (resolvedMethod == null) {
return null;
}
if (resolvedMethod.getKind() == ElementKind.CONSTRUCTOR) {
return resolvedMethod.getEnclosingElement().asType();
} else {
return resolvedMethod.getReturnType();
}
}
public ExecutableElement getResolvedMethod() {
return resolvedMethod;
}
public void setResolvedMethod(ExecutableElement resolvedMethod) {
this.resolvedMethod = resolvedMethod;
}
@Override
public String toString() {
return "Call [receiver=" + receiver + ", name=" + name + ", parameters=" + parameters + ", resolvedMethod=" + resolvedMethod + "]";
}
}
public static final class Variable extends DSLExpression {
private final DSLExpression receiver;
private final String name;
private VariableElement resolvedVariable;
public Variable(DSLExpression receiver, String name) {
this.receiver = receiver;
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Variable) {
Variable other = (Variable) obj;
return Objects.equals(receiver, other.receiver) && name.equals(other.name);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(receiver, name);
}
public DSLExpression getReceiver() {
return receiver;
}
public String getName() {
return name;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
if (receiver != null) {
receiver.accept(visitor);
}
visitor.visitVariable(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer reducer) {
DSLExpression newReceiver = null;
if (receiver != null) {
newReceiver = receiver.reduceImpl(reducer);
}
Variable c = this;
if (newReceiver != receiver) {
c = new Variable(newReceiver, getName());
c.setResolvedTargetType(getResolvedTargetType());
c.setResolvedVariable(getResolvedVariable());
}
return reducer.visitVariable(c);
}
@Override
public TypeMirror getResolvedType() {
return resolvedVariable != null ? resolvedVariable.asType() : null;
}
public void setResolvedVariable(VariableElement resolvedVariable) {
this.resolvedVariable = resolvedVariable;
}
public VariableElement getResolvedVariable() {
return resolvedVariable;
}
@Override
public String toString() {
return "Variable [receiver=" + receiver + ", name=" + name + ", resolvedVariable=" + resolvedVariable + "]";
}
}
public static final class IntLiteral extends DSLExpression {
private final String literal;
private int resolvedValueInt;
private TypeMirror resolvedType;
public IntLiteral(String literal) {
this.literal = literal;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IntLiteral) {
IntLiteral other = (IntLiteral) obj;
return resolvedValueInt == other.resolvedValueInt;
}
return false;
}
@Override
public Object resolveConstant() {
return resolvedValueInt;
}
@Override
public int hashCode() {
return resolvedValueInt;
}
public String getLiteral() {
return literal;
}
public int getResolvedValueInt() {
return resolvedValueInt;
}
public void setResolvedValueInt(int resolved) {
this.resolvedValueInt = resolved;
}
@Override
public TypeMirror getResolvedType() {
return resolvedType;
}
public void setResolvedType(TypeMirror resolvedType) {
this.resolvedType = resolvedType;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
visitor.visitIntLiteral(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer reducer) {
return this;
}
@Override
public String toString() {
return "IntLiteral [literal=" + literal + ", resolvedValueInt=" + resolvedValueInt + ", resolvedType=" + resolvedType + "]";
}
}
public static final class BooleanLiteral extends DSLExpression {
private final boolean literal;
private TypeMirror resolvedType;
public BooleanLiteral(boolean literal) {
this.literal = literal;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BooleanLiteral) {
BooleanLiteral other = (BooleanLiteral) obj;
return literal == other.literal;
}
return false;
}
@Override
public Object resolveConstant() {
return literal;
}
@Override
public int hashCode() {
return Boolean.hashCode(literal);
}
public boolean getLiteral() {
return literal;
}
@Override
public TypeMirror getResolvedType() {
return resolvedType;
}
public void setResolvedType(TypeMirror resolvedType) {
this.resolvedType = resolvedType;
}
@Override
public void accept(DSLExpressionVisitor visitor) {
visitor.visitBooleanLiteral(this);
}
@Override
public DSLExpression reduce(DSLExpressionReducer reducer) {
return this;
}
@Override
public String toString() {
return "BooleanLiteral [literal=" + literal + ", resolvedType=" + resolvedType + "]";
}
}
public abstract class AbstractDSLExpressionVisitor implements DSLExpressionVisitor {
@Override
public void visitBinary(Binary binary) {
}
@Override
public void visitCall(Call binary) {
}
@Override
public void visitIntLiteral(IntLiteral binary) {
}
@Override
public void visitNegate(Negate negate) {
}
@Override
public void visitVariable(Variable binary) {
}
public void visitBooleanLiteral(BooleanLiteral binary) {
}
}
public interface DSLExpressionVisitor {
void visitBinary(Binary binary);
void visitNegate(Negate negate);
void visitCall(Call binary);
void visitVariable(Variable binary);
void visitIntLiteral(IntLiteral binary);
void visitBooleanLiteral(BooleanLiteral binary);
}
public abstract static class AbstractDSLExpressionReducer implements DSLExpressionReducer {
@Override
public DSLExpression visitBinary(Binary binary) {
return binary;
}
@Override
public DSLExpression visitCall(Call binary) {
return binary;
}
@Override
public DSLExpression visitNegate(Negate negate) {
return negate;
}
@Override
public DSLExpression visitVariable(Variable binary) {
return binary;
}
}
public interface DSLExpressionReducer {
DSLExpression visitBinary(Binary binary);
DSLExpression visitNegate(Negate negate);
DSLExpression visitCall(Call binary);
DSLExpression visitVariable(Variable binary);
}
}