package org.activityinfo.model.expr; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import org.activityinfo.model.expr.eval.EvalContext; import org.activityinfo.model.expr.functions.ExprFunction; import org.activityinfo.model.type.FieldType; import org.activityinfo.model.type.FieldValue; import javax.annotation.Nonnull; import java.util.Arrays; import java.util.List; public class FunctionCallNode extends ExprNode { @Nonnull private ExprFunction function; @Nonnull private List<ExprNode> arguments; public FunctionCallNode(ExprFunction function, List<ExprNode> arguments) { super(); this.function = function; this.arguments = arguments; } public FunctionCallNode(ExprFunction function, ExprNode... arguments) { this(function, Arrays.asList(arguments)); } @Override public FieldValue evaluate(EvalContext context) { List<FieldValue> evaluatedArguments = Lists.newArrayList(); for (ExprNode expr : arguments) { evaluatedArguments.add(expr.evaluate(context)); } return function.apply(evaluatedArguments); } @Override public FieldType resolveType(EvalContext context) { List<FieldType> argumentTypes = Lists.newArrayList(); for (ExprNode expr : arguments) { argumentTypes.add(expr.resolveType(context)); } return function.resolveResultType(argumentTypes); } @Nonnull public ExprFunction getFunction() { return function; } @Nonnull public List<ExprNode> getArguments() { return arguments; } @Override public String toString() { return "(" + function.getId() + " " + Joiner.on(" ").join(arguments) + ")"; } @Override public String asExpression() { if (ExprParser.FUNCTIONS.contains(function.getId())) { String argumentString = ""; for (ExprNode arg : arguments) { argumentString += arg; if (!arg.equals(arguments.get(arguments.size() - 1))) { // add comma if not last element argumentString += ","; } } return function.getId() + "(" + argumentString + ")"; } else { return arguments.get(0).asExpression() + "" + function.getId() + "" + arguments.get(1).asExpression(); } } @Override public <T> T accept(ExprVisitor<T> visitor) { return visitor.visitFunctionCall(this); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (arguments.hashCode()); result = prime * result + (function.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FunctionCallNode other = (FunctionCallNode) obj; return other.function.equals(function) && other.arguments.equals(arguments); } }