/*******************************************************************************
* Copyright (c) 2011 Cloudsmith Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cloudsmith Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.p2.metadata.expression;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import org.eclipse.equinox.p2.metadata.expression.*;
import org.eclipse.equinox.p2.query.IQuery;
public class ExpressionFactory implements IExpressionFactory, IExpressionConstants {
public static final Variable EVERYTHING = new Variable(VARIABLE_EVERYTHING);
protected static final Map<String, Constructor<?>> functionMap;
public static final IExpressionFactory INSTANCE = new ExpressionFactory();
public static final Variable THIS = new Variable(VARIABLE_THIS);
static {
Class<?>[] args = new Class[] {Expression[].class};
Map<String, Constructor<?>> f = new HashMap<String, Constructor<?>>();
try {
f.put(KEYWORD_BOOLEAN, BooleanFunction.class.getConstructor(args));
f.put(KEYWORD_FILTER, FilterFunction.class.getConstructor(args));
f.put(KEYWORD_VERSION, VersionFunction.class.getConstructor(args));
f.put(KEYWORD_RANGE, RangeFunction.class.getConstructor(args));
f.put(KEYWORD_CLASS, ClassFunction.class.getConstructor(args));
f.put(KEYWORD_SET, SetFunction.class.getConstructor(args));
f.put(KEYWORD_IQUERY, WrappedIQuery.class.getConstructor(args));
functionMap = Collections.unmodifiableMap(f);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
protected static Expression[] convertArray(IExpression[] operands) {
Expression[] ops = new Expression[operands.length];
System.arraycopy(operands, 0, ops, 0, operands.length);
return ops;
}
public IExpression all(IExpression collection, IExpression lambda) {
return new All((Expression) collection, (LambdaExpression) lambda);
}
public IExpression and(IExpression... operands) {
if (operands.length == 0)
return Literal.TRUE_CONSTANT;
if (operands.length == 1)
return operands[0];
return new And(convertArray(operands));
}
public IExpression array(IExpression... operands) {
return new Array(convertArray(operands));
}
public IExpression assignment(IExpression variable, IExpression expression) {
return new Assignment((Variable) variable, (Expression) expression);
}
public IExpression at(IExpression target, IExpression key) {
return new At((Expression) target, (Expression) key);
}
public IExpression collect(IExpression collection, IExpression lambda) {
return new Collect((Expression) collection, (LambdaExpression) lambda);
}
public IExpression condition(IExpression test, IExpression ifTrue, IExpression ifFalse) {
return new Condition((Expression) test, (Expression) ifTrue, (Expression) ifFalse);
}
public IExpression constant(Object value) {
return Literal.create(value);
}
@SuppressWarnings("unchecked")
public <T> IContextExpression<T> contextExpression(IExpression expression, Object... parameters) {
if (expression instanceof IContextExpression<?>) {
if (parameters.length > 0)
// Not good.
throw new IllegalArgumentException("IContextExpression cannot be parameterized (it already is)"); //$NON-NLS-1$
return (IContextExpression<T>) expression;
}
if (expression instanceof IMatchExpression<?>)
throw new IllegalArgumentException("IMatchExpression cannot be turned into a context expression"); //$NON-NLS-1$
return new ContextExpression<T>((Expression) expression, parameters);
}
public IEvaluationContext createContext(IExpression[] variables, Object... parameters) {
return EvaluationContext.create(parameters, variables);
}
public IEvaluationContext createContext(Object... parameters) {
return EvaluationContext.create(parameters, (Variable[]) null);
}
public IExpression equals(IExpression lhs, IExpression rhs) {
return new Equals((Expression) lhs, (Expression) rhs, false);
}
public IExpression exists(IExpression collection, IExpression lambda) {
return new Exists((Expression) collection, (LambdaExpression) lambda);
}
public IFilterExpression filterExpression(IExpression expression) {
return new LDAPFilter((Expression) expression);
}
public IExpression first(IExpression collection, IExpression lambda) {
return new First((Expression) collection, (LambdaExpression) lambda);
}
public IExpression flatten(IExpression collection) {
return new Flatten((Expression) collection);
}
public IExpression function(Object function, IExpression... args) {
try {
return (IExpression) ((Constructor<?>) function).newInstance(new Object[] {convertArray(args)});
} catch (IllegalArgumentException e) {
throw e;
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException)
throw (RuntimeException) t;
throw new RuntimeException(t);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public Map<String, ? extends Object> getFunctionMap() {
return functionMap;
}
public IExpression greater(IExpression lhs, IExpression rhs) {
return new Compare((Expression) lhs, (Expression) rhs, false, false);
}
public IExpression greaterEqual(IExpression lhs, IExpression rhs) {
return new Compare((Expression) lhs, (Expression) rhs, false, true);
}
public IExpression indexedParameter(int index) {
return new Parameter(index);
}
public IExpression intersect(IExpression c1, IExpression c2) {
return new Intersect((Expression) c1, (Expression) c2);
}
public IExpression lambda(IExpression variable, IExpression body) {
return new LambdaExpression((Variable) variable, (Expression) body);
}
public IExpression lambda(IExpression variable, IExpression[] assignments, IExpression body) {
if (assignments.length == 0)
return lambda(variable, body);
Assignment[] asgns = new Assignment[assignments.length];
System.arraycopy(assignments, 0, asgns, 0, assignments.length);
return new CurryedLambdaExpression((Variable) variable, asgns, (Expression) body);
}
public IExpression latest(IExpression collection) {
return new Latest((Expression) collection);
}
public IExpression less(IExpression lhs, IExpression rhs) {
return new Compare((Expression) lhs, (Expression) rhs, true, false);
}
public IExpression lessEqual(IExpression lhs, IExpression rhs) {
return new Compare((Expression) lhs, (Expression) rhs, true, true);
}
public IExpression limit(IExpression collection, IExpression limit) {
return new Limit((Expression) collection, (Expression) limit);
}
public IExpression limit(IExpression collection, int count) {
return new Limit((Expression) collection, Literal.create(new Integer(count)));
}
public IExpression matches(IExpression lhs, IExpression rhs) {
return new Matches((Expression) lhs, (Expression) rhs);
}
@SuppressWarnings("unchecked")
public <T> IMatchExpression<T> matchExpression(IExpression expression, Object... parameters) {
if (expression instanceof IMatchExpression<?>) {
if (parameters.length > 0)
// Not good.
throw new IllegalArgumentException("IMatchExpression cannot be parameterized (it already is)"); //$NON-NLS-1$
return (IMatchExpression<T>) expression;
}
if (expression instanceof IContextExpression<?>)
throw new IllegalArgumentException("IContextExpression cannot be turned into a match expression"); //$NON-NLS-1$
return new MatchExpression<T>((Expression) expression, parameters);
}
public IExpression member(IExpression target, String name) {
if ("empty".equals(name)) //$NON-NLS-1$
return new Member.EmptyMember((Expression) target);
if ("length".equals(name)) //$NON-NLS-1$
return new Member.LengthMember((Expression) target);
return new Member.DynamicMember((Expression) target, name);
}
public IExpression memberCall(IExpression target, String name, IExpression... args) {
if (args.length == 0)
return member(target, name);
Expression[] eargs = convertArray(args);
// Insert functions that takes arguments here
//
StringBuffer bld = new StringBuffer();
bld.append("Don't know how to do a member call with "); //$NON-NLS-1$
bld.append(name);
bld.append('(');
Expression.elementsToString(bld, null, eargs);
bld.append(')');
throw new IllegalArgumentException(bld.toString());
}
@SuppressWarnings("unchecked")
public IExpression normalize(List<? extends IExpression> operands, int expressionType) {
return Expression.normalize((List<Expression>) operands, expressionType);
}
public IExpression not(IExpression operand) {
if (operand instanceof Equals) {
Equals eq = (Equals) operand;
return new Equals(eq.lhs, eq.rhs, !eq.negate);
}
if (operand instanceof Compare) {
Compare cmp = (Compare) operand;
return new Compare(cmp.lhs, cmp.rhs, !cmp.compareLess, !cmp.equalOK);
}
if (operand instanceof Not)
return ((Not) operand).operand;
return new Not((Expression) operand);
}
public IExpression or(IExpression... operands) {
if (operands.length == 0)
return Literal.TRUE_CONSTANT;
if (operands.length == 1)
return operands[0];
return new Or(convertArray(operands));
}
public IExpression pipe(IExpression... operands) {
return Pipe.createPipe(convertArray(operands));
}
public IExpression select(IExpression collection, IExpression lambda) {
return new Select((Expression) collection, (LambdaExpression) lambda);
}
public IExpression thisVariable() {
return THIS;
}
public IExpression toExpression(IQuery<?> query) {
Literal queryConstant = Literal.create(query);
return new WrappedIQuery(new Expression[] {queryConstant});
}
public IExpression traverse(IExpression collection, IExpression lambda) {
return new Traverse((Expression) collection, (LambdaExpression) lambda);
}
public IExpression union(IExpression c1, IExpression c2) {
return new Union((Expression) c1, (Expression) c2);
}
public IExpression unique(IExpression collection, IExpression cache) {
return new Unique((Expression) collection, (Expression) cache);
}
public IExpression variable(String name) {
if (VARIABLE_EVERYTHING.equals(name))
return EVERYTHING;
if (VARIABLE_THIS.equals(name))
return THIS;
return new Variable(name);
}
}