/******************************************************************************* * Copyright (c) 2005, 2009 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.internal.xtend.type.baseimpl.types; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.internal.xtend.type.baseimpl.OperationImpl; import org.eclipse.xtend.expression.TypeSystem; import org.eclipse.xtend.typesystem.Feature; import org.eclipse.xtend.typesystem.Type; /** * @author Sven Efftinge (http://www.efftinge.de) * @author Arno Haase * @author Heiko Behrens */ public final class IntegerTypeImpl extends BuiltinBaseType { public IntegerTypeImpl(final TypeSystem ts, final String name) { super(ts, name); } public boolean isInstance(final Object o) { return o instanceof BigInteger || o instanceof Integer || o instanceof Byte || o instanceof Long || o instanceof Short; } public Object newInstance() { return new BigInteger("-1"); } @Override public Feature[] getContributedFeatures() { return new Feature[] { new OperationImpl(this, "+", IntegerTypeImpl.this, new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (params[0] == null) return null; return toInt(target).add(toInt(params[0])); } }, new OperationImpl(this, "-", IntegerTypeImpl.this, new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (params[0] == null) return null; return toInt(target).subtract(toInt(params[0])); } }, new OperationImpl(this, "-", IntegerTypeImpl.this, new Type[] {}) { @Override public Object evaluateInternal(final Object target, final Object[] params) { return toInt(target).negate(); } }, new OperationImpl(this, "*", IntegerTypeImpl.this, new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (params[0] == null) return null; return toInt(target).multiply(toInt(params[0])); } }, new OperationImpl(this, "/", IntegerTypeImpl.this, new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (params[0] == null) return null; return toInt(target).divide(toInt(params[0])); } }, new OperationImpl(this, "==", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return new Boolean(target == params[0]); try { return toInt(target).equals(toInt(params[0])); } catch (Exception exc) { return false; } } }, new OperationImpl(this, "!=", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return params[0] != null; try { return ! toInt(target).equals(toInt(params[0])); } catch (Exception exc) { return true; } } }, new OperationImpl(this, ">", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return Boolean.FALSE; if (params[0] == null) return Boolean.FALSE; try { return toInt(target).compareTo(toInt(params[0])) > 0; } catch (Exception exc) { return Boolean.FALSE; } } }, new OperationImpl(this, ">=", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return params[0] == null ? Boolean.TRUE : Boolean.FALSE; if (params[0] == null) return Boolean.FALSE; try { return toInt(target).compareTo(toInt(params[0])) >= 0; } catch (Exception exc) { return Boolean.FALSE; } } }, new OperationImpl(this, "<", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return Boolean.FALSE; if (params[0] == null) return Boolean.FALSE; try { return toInt(target).compareTo(toInt(params[0])) < 0; } catch (Exception exc) { return Boolean.FALSE; } } }, new OperationImpl(this, "<=", getTypeSystem().getBooleanType(), new Type[] { IntegerTypeImpl.this }) { @Override public Object evaluateInternal(final Object target, final Object[] params) { if (target == null) return params[0] == null ? Boolean.TRUE : Boolean.FALSE; if (params[0] == null) return Boolean.FALSE; try { return toInt(target).compareTo(toInt(params[0])) <= 0; } catch (Exception exc) { return Boolean.FALSE; } } }, new OperationImpl(this, "upTo", getTypeSystem().getListType(this), new Type[] { this }) { @Override public String getDocumentation() { return "returns a List of Integers starting with the value of the target expression, up to " + "the value of the specified Integer, incremented by one.<br/>" + "e.g. '1.upTo(5)' evaluates to {1,2,3,4,5}"; } @Override public Object evaluateInternal(final Object target, final Object[] params) { final List<BigInteger> result = new ArrayList<BigInteger>(); BigInteger l1 = toInt(target); final BigInteger l2 = toInt(params[0]); while (l1.compareTo(l2) <= 0) { result.add(l1); l1 = l1.add(BigInteger.ONE); } return result; } }, new OperationImpl(this, "upTo", getTypeSystem().getListType(this), new Type[] { this, this }) { @Override public String getDocumentation() { return "returns a List of Integers starting with the value of the target expression, up to " + "the value of the first paramter, incremented by the second parameter.<br/>" + "e.g. '1.upTo(10, 2)' evaluates to {1,3,5,7,9}"; } @Override public Object evaluateInternal(final Object target, final Object[] params) { final List<BigInteger> result = new ArrayList<BigInteger>(); BigInteger l1 = toInt(target); final BigInteger l2 = toInt(params[0]); final BigInteger l3 = toInt(params[1]); while (l1.compareTo(l2) <= 0) { result.add(l1); l1 = l1.add(l3); } return result; } } }; } @Override public Set<Type> getSuperTypes() { return Collections.singleton(getTypeSystem().getRealType()); } protected BigInteger toInt(final Object o) { if(o == null) return null; if (o instanceof BigInteger) return (BigInteger) o; if (o instanceof Integer) return BigInteger.valueOf(((Integer)o).longValue()); else if (o instanceof Byte) return BigInteger.valueOf(((Byte)o).longValue()); else if (o instanceof Long) return BigInteger.valueOf((Long)o); else if (o instanceof Short) return BigInteger.valueOf(((Short) o).longValue()); throw new IllegalArgumentException(o.getClass().getName() + " not supported"); } @Override public Object convert(final Object src, final Class<?> targetType) { final BigInteger value = toInt(src); if (targetType.isAssignableFrom(BigInteger.class)) return value; else if (targetType.isAssignableFrom(Long.class) || targetType.isAssignableFrom(Long.TYPE)) return value.longValue(); else if (targetType.isAssignableFrom(Integer.class) || targetType.isAssignableFrom(Integer.TYPE)) return value.intValue(); else if (targetType.isAssignableFrom(Byte.class) || targetType.isAssignableFrom(Byte.TYPE)) return value.byteValue(); else if (targetType.isAssignableFrom(Short.class) || targetType.isAssignableFrom(Short.TYPE)) return value.shortValue(); return super.convert(src, targetType); } }