/src/main/java/org/mvel2/util/ParseTools.java
Java | 2259 lines | 2054 code | 174 blank | 31 comment | 446 complexity | c8ba485665d937261d01740cb3abc4d9 MD5 | raw file
Possible License(s): Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /**
- * MVEL 2.0
- * Copyright (C) 2007 The Codehaus
- * Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.mvel2.util;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Serializable;
- import java.lang.ref.WeakReference;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Executable;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.math.MathContext;
- import java.nio.ByteBuffer;
- import java.nio.channels.ReadableByteChannel;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.WeakHashMap;
- import org.mvel2.CompileException;
- import org.mvel2.DataTypes;
- import org.mvel2.MVEL;
- import org.mvel2.Operator;
- import org.mvel2.OptimizationFailure;
- import org.mvel2.ParserContext;
- import org.mvel2.ast.ASTNode;
- import org.mvel2.compiler.AbstractParser;
- import org.mvel2.compiler.BlankLiteral;
- import org.mvel2.compiler.CompiledExpression;
- import org.mvel2.compiler.ExecutableAccessor;
- import org.mvel2.compiler.ExecutableAccessorSafe;
- import org.mvel2.compiler.ExecutableLiteral;
- import org.mvel2.compiler.ExpressionCompiler;
- import org.mvel2.integration.VariableResolverFactory;
- import org.mvel2.integration.impl.ClassImportResolverFactory;
- import org.mvel2.math.MathProcessor;
- import static java.lang.Class.forName;
- import static java.lang.Double.parseDouble;
- import static java.lang.String.valueOf;
- import static java.lang.System.arraycopy;
- import static java.lang.Thread.currentThread;
- import static java.nio.ByteBuffer.allocateDirect;
- import static org.mvel2.DataConversion.canConvert;
- import static org.mvel2.DataTypes.*;
- import static org.mvel2.MVEL.getDebuggingOutputFileName;
- import static org.mvel2.compiler.AbstractParser.LITERALS;
- import static org.mvel2.integration.ResolverTools.appendFactory;
- @SuppressWarnings({"ManualArrayCopy"})
- public class ParseTools {
- public static final Object[] EMPTY_OBJ_ARR = new Object[0];
- public static final Class[] EMPTY_CLS_ARR = new Class[0];
- public static List<char[]> parseMethodOrConstructor(char[] parm) {
- int start = -1;
- for (int i = 0; i < parm.length; i++) {
- if (parm[i] == '(') {
- start = ++i;
- break;
- }
- }
- if (start != -1) {
- return parseParameterList(parm, --start + 1, balancedCapture(parm, start, '(') - start - 1);
- }
- return Collections.emptyList();
- }
- public static String[] parseParameterDefList(char[] parm, int offset, int length) {
- List<String> list = new LinkedList<String>();
- if (length == -1)
- length = parm.length;
- int start = offset;
- int i = offset;
- int end = i + length;
- String s;
- for (; i < end; i++) {
- switch (parm[i]) {
- case '(':
- case '[':
- case '{':
- i = balancedCapture(parm, i, parm[i]);
- continue;
- case '\'':
- i = captureStringLiteral('\'', parm, i, parm.length);
- continue;
- case '"':
- i = captureStringLiteral('"', parm, i, parm.length);
- continue;
- case ',':
- if (i > start) {
- while (isWhitespace(parm[start]))
- start++;
- checkNameSafety(s = new String(parm, start, i - start));
- list.add(s);
- }
- while (isWhitespace(parm[i]))
- i++;
- start = i + 1;
- continue;
- default:
- if (!isWhitespace(parm[i]) && !isIdentifierPart(parm[i])) {
- throw new CompileException("expected parameter", parm, start);
- }
- }
- }
- if (start < (length + offset) && i > start) {
- if ((s = createStringTrimmed(parm, start, i - start)).length() > 0) {
- checkNameSafety(s);
- list.add(s);
- }
- }
- else if (list.size() == 0) {
- if ((s = createStringTrimmed(parm, start, length)).length() > 0) {
- checkNameSafety(s);
- list.add(s);
- }
- }
- return list.toArray(new String[list.size()]);
- }
- public static List<char[]> parseParameterList(char[] parm, int offset, int length) {
- List<char[]> list = new ArrayList<char[]>();
- if (length == -1)
- length = parm.length;
- int start = offset;
- int i = offset;
- int end = i + length;
- for (; i < end; i++) {
- switch (parm[i]) {
- case '(':
- case '[':
- case '{':
- i = balancedCapture(parm, i, parm[i]);
- continue;
- case '\'':
- i = captureStringLiteral('\'', parm, i, parm.length);
- continue;
- case '"':
- i = captureStringLiteral('"', parm, i, parm.length);
- continue;
- case ',':
- if (i > start) {
- while (isWhitespace(parm[start]))
- start++;
- list.add(subsetTrimmed(parm, start, i - start));
- }
- while (isWhitespace(parm[i]))
- i++;
- start = i + 1;
- }
- }
- if (start < (length + offset) && i > start) {
- char[] s = subsetTrimmed(parm, start, i - start);
- if (s.length > 0)
- list.add(s);
- }
- else if (list.size() == 0) {
- char[] s = subsetTrimmed(parm, start, length);
- if (s.length > 0)
- list.add(s);
- }
- return list;
- }
- public static Method getBestCandidate(Object[] arguments, String method, Class decl, Method[] methods, boolean requireExact) {
- Class[] targetParms = new Class[arguments.length];
- for (int i = 0; i != arguments.length; i++) {
- targetParms[i] = arguments[i] != null ? arguments[i].getClass() : null;
- }
- return getBestCandidate(targetParms, method, decl, methods, requireExact);
- }
- public static Method getBestCandidate(Class[] arguments, String method, Class decl, Method[] methods, boolean requireExact) {
- return getBestCandidate(arguments, method, decl, methods, requireExact, false);
- }
- public static Method getBestCandidate(Class[] arguments, String method, Class decl, Method[] methods, boolean requireExact, boolean classTarget) {
- if (methods.length == 0) {
- return null;
- }
- Class<?>[] parmTypes;
- Method bestCandidate = null;
- int bestScore = -1;
- boolean retry = false;
- do {
- for (Method meth : methods) {
- if (classTarget && !Modifier.isStatic(meth.getModifiers())) continue;
- if (method.equals(meth.getName())) {
- parmTypes = meth.getParameterTypes();
- if (parmTypes.length == 0 && arguments.length == 0) {
- if (bestCandidate == null || isMoreSpecialized(meth, bestCandidate) ) {
- bestCandidate = meth;
- }
- continue;
- }
- boolean isVarArgs = meth.isVarArgs();
- if ( isArgsNumberNotCompatible( arguments, parmTypes, isVarArgs ) ) {
- continue;
- }
- int score = getMethodScore(arguments, requireExact, parmTypes, isVarArgs);
- if (score != 0) {
- if (score > bestScore) {
- bestCandidate = meth;
- bestScore = score;
- }
- else if (score == bestScore) {
- if ((isMoreSpecialized(meth, bestCandidate) || isMorePreciseForBigDecimal(meth, bestCandidate, arguments))&& !isVarArgs) {
- bestCandidate = meth;
- }
- }
- }
- }
- }
- if (bestCandidate != null) {
- break;
- }
- if (!retry && decl.isInterface()) {
- Method[] objMethods = Object.class.getMethods();
- Method[] nMethods = new Method[methods.length + objMethods.length];
- for (int i = 0; i < methods.length; i++) {
- nMethods[i] = methods[i];
- }
- for (int i = 0; i < objMethods.length; i++) {
- nMethods[i + methods.length] = objMethods[i];
- }
- methods = nMethods;
- retry = true;
- }
- else {
- break;
- }
- }
- while (true);
- return bestCandidate;
- }
- private static boolean isArgsNumberNotCompatible( Class[] arguments, Class<?>[] parmTypes, boolean isVarArgs ) {
- return ( isVarArgs && parmTypes.length-1 > arguments.length ) || ( !isVarArgs && parmTypes.length != arguments.length );
- }
- private static boolean isMoreSpecialized( Method newCandidate, Method oldCandidate ) {
- return oldCandidate.getReturnType().isAssignableFrom( newCandidate.getReturnType()) &&
- oldCandidate.getDeclaringClass().isAssignableFrom( newCandidate.getDeclaringClass());
- }
- private static boolean isMorePreciseForBigDecimal(Executable newCandidate, Executable oldCandidate, Class[] arguments) {
- Class<?>[] newParmTypes = newCandidate.getParameterTypes();
- Class<?>[] oldParmTypes = oldCandidate.getParameterTypes();
- int score = 0;
- for (int i = 0; i != arguments.length; i++) {
- Class<?> newParmType = newParmTypes[i];
- Class<?> oldParmType = oldParmTypes[i];
- if (arguments[i] != BigDecimal.class || !isNumeric(oldParmType) || !isNumeric(newParmType)) {
- continue;
- }
- score += comparePrecision(unboxPrimitive(newParmType), unboxPrimitive(oldParmType));
- }
- return (score > 0);
- }
- private static int comparePrecision(Class<?> numeric1, Class<?> numeric2) {
- if (numeric1 == numeric2) {
- return 0;
- }
- if (numeric1 == BigDecimal.class) {
- return 1;
- } else if ((numeric1 == double.class) && (numeric2 == float.class || numeric2 == long.class || numeric2 == int.class || numeric2 == short.class || numeric2 == BigInteger.class)) {
- return 1;
- } else if ((numeric1 == float.class) && (numeric2 == long.class || numeric2 == int.class || numeric2 == short.class || numeric2 == BigInteger.class)) {
- // float is preferred over long/BigInteger assuming users don't want to lose decimal part
- return 1;
- } else if ((numeric1 == BigInteger.class) && (numeric2 == long.class || numeric2 == int.class || numeric2 == short.class)) {
- return 1;
- } else if ((numeric1 == long.class) && (numeric2 == int.class || numeric2 == short.class)) {
- return 1;
- } else if ((numeric1 == int.class) && numeric2 == short.class) {
- return 1;
- } else {
- return -1;
- }
- }
- private static int getMethodScore(Class[] arguments, boolean requireExact, Class<?>[] parmTypes, boolean varArgs) {
- int score = 0;
- for (int i = 0; i != arguments.length; i++) {
- Class<?> actualParamType;
- if (varArgs && i >= parmTypes.length - 1)
- actualParamType = parmTypes[parmTypes.length - 1].getComponentType();
- else
- actualParamType = parmTypes[i];
- if (arguments[i] == null) {
- if (!actualParamType.isPrimitive()) {
- score += 7;
- }
- else {
- score = 0;
- break;
- }
- }
- else if (actualParamType == arguments[i]) {
- score += 8;
- }
- else if (actualParamType.isPrimitive() && boxPrimitive(actualParamType) == arguments[i]) {
- score += 7;
- }
- else if (arguments[i].isPrimitive() && unboxPrimitive(arguments[i]) == actualParamType) {
- score += 7;
- }
- else if (actualParamType.isAssignableFrom(arguments[i])) {
- score += 6;
- }
- else if (isPrimitiveSubtype(arguments[i], actualParamType)) {
- score += 5;
- }
- else if (isNumericallyCoercible(arguments[i], actualParamType)) {
- score += 4;
- }
- else if (boxPrimitive(actualParamType).isAssignableFrom(boxPrimitive(arguments[i]))
- && Object.class != arguments[i]) {
- score += 3 + scoreInterface(actualParamType, arguments[i]);
- }
- else if (!requireExact && canConvert(actualParamType, arguments[i])) {
- if (actualParamType.isArray() && arguments[i].isArray()) score += 1;
- else if (actualParamType == char.class && arguments[i] == String.class) score += 1;
- score += 1;
- }
- else if (actualParamType == Object.class || arguments[i] == NullType.class) {
- score += 1;
- }
- else {
- score = 0;
- break;
- }
- }
- if (score == 0 && varArgs && parmTypes.length - 1 == arguments.length) {
- score += 3;
- }
- return score;
- }
- public static int scoreInterface(Class<?> parm, Class<?> arg) {
- if (parm.isInterface()) {
- Class[] iface = arg.getInterfaces();
- if (iface != null) {
- for (Class c : iface) {
- if (c == parm) return 1;
- else if (parm.isAssignableFrom(c)) return scoreInterface(parm, arg.getSuperclass());
- }
- }
- }
- return 0;
- }
- public static Method getExactMatch(String name, Class[] args, Class returnType, Class cls) {
- outer:
- for (Method meth : cls.getMethods()) {
- if (name.equals(meth.getName()) && returnType == meth.getReturnType()) {
- Class[] parameterTypes = meth.getParameterTypes();
- if (parameterTypes.length != args.length) continue;
- for (int i = 0; i < parameterTypes.length; i++) {
- if (parameterTypes[i] != args[i]) continue outer;
- }
- return meth;
- }
- }
- return null;
- }
- public static Method getWidenedTarget(Method method) {
- return getWidenedTarget(method.getDeclaringClass(), method);
- }
- public static Method getWidenedTarget(Class cls, Method method) {
- if (Modifier.isStatic(method.getModifiers())) {
- return method;
- }
- Method m = method, best = method;
- Class[] args = method.getParameterTypes();
- String name = method.getName();
- Class rt = m.getReturnType();
- Class currentCls = cls;
- while (currentCls != null) {
- for (Class iface : currentCls.getInterfaces()) {
- if ((m = getExactMatch(name, args, rt, iface)) != null) {
- best = m;
- }
- }
- currentCls = currentCls.getSuperclass();
- }
- if (best != method) return best;
- for (currentCls = cls; currentCls != null; currentCls = currentCls.getSuperclass()) {
- if ((m = getExactMatch(name, args, rt, currentCls)) != null) {
- best = m;
- }
- }
- return best;
- }
- private static final Map<Constructor, WeakReference<Class[]>> CONSTRUCTOR_PARMS_CACHE
- = Collections.synchronizedMap( new WeakHashMap<Constructor, WeakReference<Class[]>>(10) );
- private static Class[] getConstructors(Constructor cns) {
- WeakReference<Class[]> ref = CONSTRUCTOR_PARMS_CACHE.get(cns);
- Class[] parms;
- if (ref != null && (parms = ref.get()) != null) {
- return parms;
- }
- else {
- CONSTRUCTOR_PARMS_CACHE.put(cns, new WeakReference<Class[]>(parms = cns.getParameterTypes()));
- return parms;
- }
- }
- public static Constructor getBestConstructorCandidate(Object[] args, Class cls, boolean requireExact) {
- Class[] arguments = new Class[args.length];
- for (int i = 0; i != args.length; i++) {
- if (args[i] != null) {
- arguments[i] = args[i].getClass();
- }
- }
- return getBestConstructorCandidate(arguments, cls, requireExact);
- }
- public static Constructor getBestConstructorCandidate(Class[] arguments, Class cls, boolean requireExact) {
- Class[] parmTypes;
- Constructor bestCandidate = null;
- int bestScore = 0;
- boolean bestCandidateIsVarArgs = false;
- for (Constructor construct : getConstructors(cls)) {
- boolean isVarArgs = construct.isVarArgs();
- parmTypes = getConstructors(construct);
- if ( isArgsNumberNotCompatible( arguments, parmTypes, isVarArgs ) ) {
- continue;
- }
- else if (arguments.length == 0 && parmTypes.length == 0) {
- return construct;
- }
- int score = getMethodScore(arguments, requireExact, parmTypes, isVarArgs);
- if (score != 0) {
- if (score > bestScore) {
- bestCandidate = construct;
- bestScore = score;
- bestCandidateIsVarArgs = isVarArgs;
- }
- else if (score == bestScore && (isMorePreciseForBigDecimal(construct, bestCandidate, arguments) || (bestCandidateIsVarArgs && !isVarArgs))) {
- bestCandidate = construct;
- bestCandidateIsVarArgs = isVarArgs;
- }
- }
- }
- return bestCandidate;
- }
- private static final Map<ClassLoader, Map<String, WeakReference<Class>>> CLASS_RESOLVER_CACHE
- = Collections.synchronizedMap( new WeakHashMap<ClassLoader, Map<String, WeakReference<Class>>>(1, 1.0f) );
- private static final Map<Class, WeakReference<Constructor[]>> CLASS_CONSTRUCTOR_CACHE
- = Collections.synchronizedMap( new WeakHashMap<Class, WeakReference<Constructor[]>>(10) );
- public static Class createClass(String className, ParserContext pCtx) throws ClassNotFoundException {
- ClassLoader classLoader = pCtx != null ? pCtx.getClassLoader() : currentThread().getContextClassLoader();
- Map<String, WeakReference<Class>> cache = CLASS_RESOLVER_CACHE.get(classLoader);
- if (cache == null) {
- CLASS_RESOLVER_CACHE.put(classLoader, cache = Collections.synchronizedMap( new WeakHashMap<String, WeakReference<Class>>(10) ) );
- }
- WeakReference<Class> ref;
- Class cls;
- if ((ref = cache.get(className)) != null && (cls = ref.get()) != null) {
- return cls;
- }
- else {
- try {
- cls = Class.forName(className, true, classLoader);
- }
- catch (ClassNotFoundException e) {
- /**
- * Now try the system classloader.
- */
- if (classLoader != Thread.currentThread().getContextClassLoader()) {
- cls = forName(className, true, Thread.currentThread().getContextClassLoader());
- }
- else {
- throw e;
- }
- }
- cache.put(className, new WeakReference<Class>(cls));
- return cls;
- }
- }
- public static Constructor[] getConstructors(Class cls) {
- WeakReference<Constructor[]> ref = CLASS_CONSTRUCTOR_CACHE.get(cls);
- Constructor[] cns;
- if (ref != null && (cns = ref.get()) != null) {
- return cns;
- }
- else {
- CLASS_CONSTRUCTOR_CACHE.put(cls, new WeakReference<Constructor[]>(cns = cls.getConstructors()));
- return cns;
- }
- }
- public static String[] captureContructorAndResidual(char[] cs, int start, int offset) {
- int depth = 0;
- int end = start + offset;
- boolean inQuotes = false;
- for (int i = start; i < end; i++) {
- switch (cs[i]) {
- case '"':
- inQuotes = !inQuotes;
- break;
- case '(':
- depth++;
- break;
- case ')':
- if (!inQuotes) {
- if (1 == depth--) {
- return new String[]{createStringTrimmed(cs, start, ++i - start), createStringTrimmed(cs, i, end - i)};
- }
- }
- }
- }
- return new String[]{new String(cs, start, offset)};
- }
- public static Class<?> boxPrimitive(Class cls) {
- if (cls == int.class || cls == Integer.class) {
- return Integer.class;
- }
- else if (cls == int[].class || cls == Integer[].class) {
- return Integer[].class;
- }
- else if (cls == char.class || cls == Character.class) {
- return Character.class;
- }
- else if (cls == char[].class || cls == Character[].class) {
- return Character[].class;
- }
- else if (cls == long.class || cls == Long.class) {
- return Long.class;
- }
- else if (cls == long[].class || cls == Long[].class) {
- return Long[].class;
- }
- else if (cls == short.class || cls == Short.class) {
- return Short.class;
- }
- else if (cls == short[].class || cls == Short[].class) {
- return Short[].class;
- }
- else if (cls == double.class || cls == Double.class) {
- return Double.class;
- }
- else if (cls == double[].class || cls == Double[].class) {
- return Double[].class;
- }
- else if (cls == float.class || cls == Float.class) {
- return Float.class;
- }
- else if (cls == float[].class || cls == Float[].class) {
- return Float[].class;
- }
- else if (cls == boolean.class || cls == Boolean.class) {
- return Boolean.class;
- }
- else if (cls == boolean[].class || cls == Boolean[].class) {
- return Boolean[].class;
- }
- else if (cls == byte.class || cls == Byte.class) {
- return Byte.class;
- }
- else if (cls == byte[].class || cls == Byte[].class) {
- return Byte[].class;
- }
- return cls;
- }
- public static Class unboxPrimitive(Class cls) {
- if (cls == Integer.class || cls == int.class) {
- return int.class;
- }
- else if (cls == Integer[].class || cls == int[].class) {
- return int[].class;
- }
- else if (cls == Long.class || cls == long.class) {
- return long.class;
- }
- else if (cls == Long[].class || cls == long[].class) {
- return long[].class;
- }
- else if (cls == Character.class || cls == char.class) {
- return char.class;
- }
- else if (cls == Character[].class || cls == char[].class) {
- return char[].class;
- }
- else if (cls == Short.class || cls == short.class) {
- return short.class;
- }
- else if (cls == Short[].class || cls == short[].class) {
- return short[].class;
- }
- else if (cls == Double.class || cls == double.class) {
- return double.class;
- }
- else if (cls == Double[].class || cls == double[].class) {
- return double[].class;
- }
- else if (cls == Float.class || cls == float.class) {
- return float.class;
- }
- else if (cls == Float[].class || cls == float[].class) {
- return float[].class;
- }
- else if (cls == Boolean.class || cls == boolean.class) {
- return boolean.class;
- }
- else if (cls == Boolean[].class || cls == boolean[].class) {
- return boolean[].class;
- }
- else if (cls == Byte.class || cls == byte.class) {
- return byte.class;
- }
- else if (cls == Byte[].class || cls == byte[].class) {
- return byte[].class;
- }
- return cls;
- }
- public static boolean containsCheck(Object compareTo, Object compareTest) {
- if (compareTo == null)
- return false;
- else if (compareTo instanceof String)
- return ((String) compareTo).contains(valueOf(compareTest));
- else if (compareTo instanceof Collection)
- return ((Collection) compareTo).contains(compareTest);
- else if (compareTo instanceof Map)
- return ((Map) compareTo).containsKey(compareTest);
- else if (compareTo.getClass().isArray()) {
- if (compareTo.getClass().getComponentType().isPrimitive())
- return containsCheckOnPrimitveArray(compareTo, compareTest);
- for (Object o : ((Object[]) compareTo)) {
- if (compareTest == null && o == null)
- return true;
- if ((Boolean) MathProcessor.doOperations(o, Operator.EQUAL, compareTest))
- return true;
- }
- }
- return false;
- }
- private static boolean containsCheckOnPrimitveArray(Object primitiveArray, Object compareTest) {
- Class<?> primitiveType = primitiveArray.getClass().getComponentType();
- if (primitiveType == boolean.class)
- return compareTest instanceof Boolean && containsCheckOnBooleanArray((boolean[]) primitiveArray, (Boolean) compareTest);
- if (primitiveType == int.class)
- return compareTest instanceof Integer && containsCheckOnIntArray((int[]) primitiveArray, (Integer) compareTest);
- if (primitiveType == long.class)
- return compareTest instanceof Long && containsCheckOnLongArray((long[]) primitiveArray, (Long) compareTest);
- if (primitiveType == double.class)
- return compareTest instanceof Double && containsCheckOnDoubleArray((double[]) primitiveArray, (Double) compareTest);
- if (primitiveType == float.class)
- return compareTest instanceof Float && containsCheckOnFloatArray((float[]) primitiveArray, (Float) compareTest);
- if (primitiveType == char.class)
- return compareTest instanceof Character && containsCheckOnCharArray((char[]) primitiveArray, (Character) compareTest);
- if (primitiveType == short.class)
- return compareTest instanceof Short && containsCheckOnShortArray((short[]) primitiveArray, (Short) compareTest);
- if (primitiveType == byte.class)
- return compareTest instanceof Byte && containsCheckOnByteArray((byte[]) primitiveArray, (Byte) compareTest);
- return false;
- }
- private static boolean containsCheckOnBooleanArray(boolean[] array, Boolean compareTest) {
- boolean test = compareTest;
- for (boolean b : array) if (b == test) return true;
- return false;
- }
- private static boolean containsCheckOnIntArray(int[] array, Integer compareTest) {
- int test = compareTest;
- for (int i : array) if (i == test) return true;
- return false;
- }
- private static boolean containsCheckOnLongArray(long[] array, Long compareTest) {
- long test = compareTest;
- for (long l : array) if (l == test) return true;
- return false;
- }
- private static boolean containsCheckOnDoubleArray(double[] array, Double compareTest) {
- double test = compareTest;
- for (double d : array) if (d == test) return true;
- return false;
- }
- private static boolean containsCheckOnFloatArray(float[] array, Float compareTest) {
- float test = compareTest;
- for (float f : array) if (f == test) return true;
- return false;
- }
- private static boolean containsCheckOnCharArray(char[] array, Character compareTest) {
- char test = compareTest;
- for (char c : array) if (c == test) return true;
- return false;
- }
- private static boolean containsCheckOnShortArray(short[] array, Short compareTest) {
- short test = compareTest;
- for (short s : array) if (s == test) return true;
- return false;
- }
- private static boolean containsCheckOnByteArray(byte[] array, Byte compareTest) {
- byte test = compareTest;
- for (byte b : array) if (b == test) return true;
- return false;
- }
- /**
- * Replace escape sequences and return trim required.
- *
- * @param escapeStr -
- * @param pos -
- * @return -
- */
- public static int handleEscapeSequence(char[] escapeStr, int pos) {
- escapeStr[pos - 1] = 0;
- switch (escapeStr[pos]) {
- case '\\':
- escapeStr[pos] = '\\';
- return 1;
- case 'b':
- escapeStr[pos] = '\b';
- return 1;
- case 'f':
- escapeStr[pos] = '\f';
- return 1;
- case 't':
- escapeStr[pos] = '\t';
- return 1;
- case 'r':
- escapeStr[pos] = '\r';
- return 1;
- case 'n':
- escapeStr[pos] = '\n';
- return 1;
- case '\'':
- escapeStr[pos] = '\'';
- return 1;
- case '"':
- escapeStr[pos] = '\"';
- return 1;
- case 'u':
- //unicode
- int s = pos;
- if (s + 4 > escapeStr.length)
- throw new CompileException("illegal unicode escape sequence", escapeStr, pos);
- else {
- while (++pos - s != 5) {
- if ((escapeStr[pos] > ('0' - 1) && escapeStr[pos] < ('9' + 1)) ||
- (escapeStr[pos] > ('A' - 1) && escapeStr[pos] < ('F' + 1))) {
- }
- else {
- throw new CompileException("illegal unicode escape sequence", escapeStr, pos);
- }
- }
- escapeStr[s - 1] = (char) Integer.decode("0x" + new String(escapeStr, s + 1, 4)).intValue();
- escapeStr[s] = 0;
- escapeStr[s + 1] = 0;
- escapeStr[s + 2] = 0;
- escapeStr[s + 3] = 0;
- escapeStr[s + 4] = 0;
- return 5;
- }
- default:
- //octal
- s = pos;
- while (escapeStr[pos] >= '0' && escapeStr[pos] < '8') {
- if (pos != s && escapeStr[s] > '3') {
- escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
- escapeStr[s] = 0;
- escapeStr[s + 1] = 0;
- return 2;
- }
- else if ((pos - s) == 2) {
- escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
- escapeStr[s] = 0;
- escapeStr[s + 1] = 0;
- escapeStr[s + 2] = 0;
- return 3;
- }
- if (pos + 1 == escapeStr.length || (escapeStr[pos] < '0' || escapeStr[pos] > '7')) {
- escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
- escapeStr[s] = 0;
- return 1;
- }
- pos++;
- }
- throw new CompileException("illegal escape sequence: " + escapeStr[pos], escapeStr, pos);
- }
- }
- public static char[] createShortFormOperativeAssignment(String name, char[] statement, int start, int offset, int operation) {
- if (operation == -1) {
- return statement;
- }
- char[] stmt;
- char op = 0;
- switch (operation) {
- case Operator.ADD:
- op = '+';
- break;
- case Operator.STR_APPEND:
- op = '#';
- break;
- case Operator.SUB:
- op = '-';
- break;
- case Operator.MULT:
- op = '*';
- break;
- case Operator.MOD:
- op = '%';
- break;
- case Operator.DIV:
- op = '/';
- break;
- case Operator.BW_AND:
- op = '&';
- break;
- case Operator.BW_OR:
- op = '|';
- break;
- case Operator.BW_SHIFT_LEFT:
- op = '\u00AB';
- break;
- case Operator.BW_SHIFT_RIGHT:
- op = '\u00BB';
- break;
- case Operator.BW_USHIFT_RIGHT:
- op = '\u00AC';
- break;
- }
- arraycopy(name.toCharArray(), 0, (stmt = new char[name.length() + offset + 1]), 0, name.length());
- stmt[name.length()] = op;
- arraycopy(statement, start, stmt, name.length() + 1, offset);
- return stmt;
- }
- public static ClassImportResolverFactory findClassImportResolverFactory(VariableResolverFactory factory, ParserContext pCtx) {
- if (factory == null) {
- throw new OptimizationFailure("unable to import classes. no variable resolver factory available.");
- }
- for (VariableResolverFactory v = factory; v != null; v = v.getNextFactory()) {
- if (v instanceof ClassImportResolverFactory) {
- return (ClassImportResolverFactory) v;
- }
- }
- return appendFactory(factory, new ClassImportResolverFactory(null, null, false));
- }
- public static Class findClass(VariableResolverFactory factory, String name, ParserContext pCtx) throws ClassNotFoundException {
- try {
- if (LITERALS.containsKey(name)) {
- return (Class) LITERALS.get(name);
- }
- else if (factory != null && factory.isResolveable(name)) {
- return (Class) factory.getVariableResolver(name).getValue();
- }
- else if (pCtx != null && pCtx.hasImport(name)) {
- return pCtx.getImport(name);
- }
- else {
- return createClass(name, pCtx);
- }
- }
- catch (ClassNotFoundException e) {
- throw e;
- }
- catch (Exception e) {
- throw new RuntimeException("class not found: " + name, e);
- }
- }
- public static char[] subsetTrimmed(char[] array, int start, int length) {
- if (length <= 0) {
- return new char[0];
- }
- int end = start + length;
- while (end > 0 && isWhitespace(array[end - 1])) {
- end--;
- }
- while (isWhitespace(array[start]) && start < end) {
- start++;
- }
- length = end - start;
- if (length == 0) {
- return new char[0];
- }
- return subset(array, start, length);
- }
- public static char[] subset(char[] array, int start, int length) {
- char[] newArray = new char[length];
- for (int i = 0; i < newArray.length; i++) {
- newArray[i] = array[i + start];
- }
- return newArray;
- }
- public static char[] subset(char[] array, int start) {
- char[] newArray = new char[array.length - start];
- for (int i = 0; i < newArray.length; i++) {
- newArray[i] = array[i + start];
- }
- return newArray;
- }
- private static final HashMap<Class, Integer> typeResolveMap = new HashMap<Class, Integer>();
- static {
- Map<Class, Integer> t = typeResolveMap;
- t.put(BigDecimal.class, DataTypes.BIG_DECIMAL);
- t.put(BigInteger.class, DataTypes.BIG_INTEGER);
- t.put(String.class, DataTypes.STRING);
- t.put(int.class, INTEGER);
- t.put(Integer.class, DataTypes.W_INTEGER);
- t.put(short.class, DataTypes.SHORT);
- t.put(Short.class, DataTypes.W_SHORT);
- t.put(float.class, DataTypes.FLOAT);
- t.put(Float.class, DataTypes.W_FLOAT);
- t.put(double.class, DOUBLE);
- t.put(Double.class, DataTypes.W_DOUBLE);
- t.put(long.class, LONG);
- t.put(Long.class, DataTypes.W_LONG);
- t.put(boolean.class, DataTypes.BOOLEAN);
- t.put(Boolean.class, DataTypes.W_BOOLEAN);
- t.put(byte.class, DataTypes.BYTE);
- t.put(Byte.class, DataTypes.W_BYTE);
- t.put(char.class, DataTypes.CHAR);
- t.put(Character.class, DataTypes.W_CHAR);
- t.put(BlankLiteral.class, DataTypes.EMPTY);
- }
- public static int resolveType(Object o) {
- if (o == null) return DataTypes.OBJECT;
- else return __resolveType(o.getClass());
- }
- private static final Map<Class, Integer> typeCodes = new HashMap<Class, Integer>(30, 0.5f);
- static {
- typeCodes.put(Integer.class, DataTypes.W_INTEGER);
- typeCodes.put(Double.class, DataTypes.W_DOUBLE);
- typeCodes.put(Boolean.class, DataTypes.W_BOOLEAN);
- typeCodes.put(String.class, DataTypes.STRING);
- typeCodes.put(Long.class, DataTypes.W_LONG);
- typeCodes.put(Short.class, DataTypes.W_SHORT);
- typeCodes.put(Float.class, DataTypes.W_FLOAT);
- typeCodes.put(Byte.class, DataTypes.W_BYTE);
- typeCodes.put(Character.class, DataTypes.W_CHAR);
- typeCodes.put(BigDecimal.class, DataTypes.BIG_DECIMAL);
- typeCodes.put(BigInteger.class, DataTypes.BIG_INTEGER);
- typeCodes.put(int.class, DataTypes.INTEGER);
- typeCodes.put(double.class, DataTypes.DOUBLE);
- typeCodes.put(boolean.class, DataTypes.BOOLEAN);
- typeCodes.put(long.class, DataTypes.LONG);
- typeCodes.put(short.class, DataTypes.SHORT);
- typeCodes.put(float.class, DataTypes.FLOAT);
- typeCodes.put(byte.class, DataTypes.BYTE);
- typeCodes.put(char.class, DataTypes.CHAR);
- typeCodes.put(BlankLiteral.class, DataTypes.EMPTY);
- }
- public static int __resolveType(Class cls) {
- Integer code = typeCodes.get(cls);
- if (code == null) {
- if (cls != null && Collection.class.isAssignableFrom(cls)) {
- return DataTypes.COLLECTION;
- }
- else {
- return DataTypes.OBJECT;
- }
- }
- return code;
- }
- private static boolean isPrimitiveSubtype( Class argument, Class<?> actualParamType ) {
- if (!actualParamType.isPrimitive()) {
- return false;
- }
- Class<?> primitiveArgument = unboxPrimitive(argument);
- if (!primitiveArgument.isPrimitive()) {
- return false;
- }
- return ( actualParamType == double.class && primitiveArgument == float.class ) ||
- ( actualParamType == float.class && primitiveArgument == long.class ) ||
- ( actualParamType == long.class && primitiveArgument == int.class ) ||
- ( actualParamType == int.class && primitiveArgument == char.class ) ||
- ( actualParamType == int.class && primitiveArgument == short.class ) ||
- ( actualParamType == short.class && primitiveArgument == byte.class );
- }
- public static boolean isNumericallyCoercible(Class target, Class parm) {
- Class boxedTarget = target.isPrimitive() ? boxPrimitive(target) : target;
- if (boxedTarget != null && Number.class.isAssignableFrom(target)) {
- if ((boxedTarget = parm.isPrimitive() ? boxPrimitive(parm) : parm) != null) {
- return Number.class.isAssignableFrom(boxedTarget);
- }
- }
- return false;
- }
- public static Object narrowType(final BigDecimal result, int returnTarget) {
- if (returnTarget == DataTypes.W_DOUBLE || result.scale() > 0) {
- return result.doubleValue();
- }
- else if (returnTarget == DataTypes.W_LONG || result.longValue() > Integer.MAX_VALUE) {
- return result.longValue();
- }
- else {
- return result.intValue();
- }
- }
- public static Method determineActualTargetMethod(Method method) {
- return determineActualTargetMethod(method.getDeclaringClass(), method);
- }
- private static Method determineActualTargetMethod(Class clazz, Method method) {
- String name = method.getName();
- /**
- * Follow our way up the class heirarchy until we find the physical target method.
- */
- for (Class cls : clazz.getInterfaces()) {
- for (Method meth : cls.getMethods()) {
- if (meth.getParameterTypes().length == 0 && name.equals(meth.getName())) {
- return meth;
- }
- }
- }
- return clazz.getSuperclass() != null ? determineActualTargetMethod(clazz.getSuperclass(), method) : null;
- }
- public static int captureToNextTokenJunction(char[] expr, int cursor, int end, ParserContext pCtx) {
- while (cursor != expr.length) {
- switch (expr[cursor]) {
- case '{':
- case '(':
- return cursor;
- case '[':
- cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '[', pCtx) + 1;
- continue;
- default:
- if (isWhitespace(expr[cursor])) {
- return cursor;
- }
- cursor++;
- }
- }
- return cursor;
- }
- public static int nextNonBlank(char[] expr, int cursor) {
- if ((cursor + 1) >= expr.length) {
- throw new CompileException("unexpected end of statement", expr, cursor);
- }
- int i = cursor;
- while (i != expr.length && isWhitespace(expr[i])) i++;
- return i;
- }
- public static int skipWhitespace(char[] expr, int cursor) {
- Skip:
- while (cursor != expr.length) {
- switch (expr[cursor]) {
- case '\n':
- case '\r':
- cursor++;
- continue;
- case '/':
- if (cursor + 1 != expr.length) {
- switch (expr[cursor + 1]) {
- case '/':
- expr[cursor++] = ' ';
- while (cursor != expr.length && expr[cursor] != '\n') expr[cursor++] = ' ';
- if (cursor != expr.length) expr[cursor++] = ' ';
- continue;
- case '*':
- int len = expr.length - 1;
- expr[cursor++] = ' ';
- while (cursor != len && !(expr[cursor] == '*' && expr[cursor + 1] == '/')) {
- expr[cursor++] = ' ';
- }
- if (cursor != len) expr[cursor++] = expr[cursor++] = ' ';
- continue;
- default:
- break Skip;
- }
- }
- default:
- if (!isWhitespace(expr[cursor])) break Skip;
- }
- cursor++;
- }
- return cursor;
- }
- public static boolean isStatementNotManuallyTerminated(char[] expr, int cursor) {
- if (cursor >= expr.length) return false;
- int c = cursor;
- while (c != expr.length && isWhitespace(expr[c])) c++;
- return !(c != expr.length && expr[c] == ';');
- }
- public static int captureToEOS(char[] expr, int cursor, int end, ParserContext pCtx) {
- while (cursor != expr.length) {
- switch (expr[cursor]) {
- case '(':
- case '[':
- case '{':
- if ((cursor = balancedCaptureWithLineAccounting(expr, cursor, end, expr[cursor], pCtx)) >= expr.length)
- return cursor;
- break;
- case '"':
- case '\'':
- cursor = captureStringLiteral(expr[cursor], expr, cursor, expr.length);
- break;
- case ',':
- case ';':
- case '}':
- return cursor;
- }
- cursor++;
- }
- return cursor;
- }
- /**
- * From the specified cursor position, trim out any whitespace between the current position and the end of the
- * last non-whitespace character.
- *
- * @param expr -
- * @param start -
- * @param pos - current position
- * @return new position.
- */
- public static int trimLeft(char[] expr, int start, int pos) {
- if (pos > expr.length) pos = expr.length;
- while (pos != 0 && pos >= start && isWhitespace(expr[pos - 1])) pos--;
- return pos;
- }
- /**
- * From the specified cursor position, trim out any whitespace between the current position and beginning of the
- * first non-whitespace character.
- *
- * @param expr -
- * @param pos -
- * @return -
- */
- public static int trimRight(char[] expr, int pos) {
- while (pos != expr.length && isWhitespace(expr[pos])) pos++;
- return pos;
- }
- public static char[] subArray(char[] expr, final int start, final int end) {
- if (start >= end) return new char[0];
- char[] newA = new char[end - start];
- for (int i = 0; i != newA.length; i++) {
- newA[i] = expr[i + start];
- }
- return newA;
- }
- /**
- * This is an important aspect of the core parser tools. This method is used throughout the core parser
- * and sub-lexical parsers to capture a balanced capture between opening and terminating tokens such as:
- * <em>( [ { ' " </em>
- * <br>
- * <br>
- * For example: ((foo + bar + (bar - foo)) * 20;<br>
- * <br>
- *
- * If a balanced capture is performed from position 2, we get "(foo + bar + (bar - foo))" back.<br>
- * If a balanced capture is performed from position 15, we get "(bar - foo)" back.<br>
- * Etc.
- *
- * @param chars -
- * @param start -
- * @param type -
- * @return -
- */
- public static int balancedCapture(char[] chars, int start, char type) {
- return balancedCapture(chars, start, chars.length, type);
- }
- public static int balancedCapture(char[] chars, int start, int end, char type) {
- int depth = 1;
- char term = type;
- switch (type) {
- case '[':
- term = ']';
- break;
- case '{':
- term = '}';
- break;
- case '(':
- term = ')';
- break;
- }
- if (type == term) {
- for (start++; start < end; start++) {
- if (chars[start] == type) {
- return start;
- }
- }
- }
- else {
- for (start++; start < end; start++) {
- if (start < end && chars[start] == '/') {
- if (start + 1 == end) return start;
- if (chars[start + 1] == '/') {
- start++;
- while (start < end && chars[start] != '\n') start++;
- }
- else if (chars[start + 1] == '*') {
- start += 2;
- SkipComment:
- while (start < end) {
- switch (chars[start]) {
- case '*':
- if (start + 1 < end && chars[start + 1] == '/') {
- break SkipComment;
- }
- case '\r':
- case '\n':
- break;
- }
- start++;
- }
- }
- }
- if (start == end) return start;
- if (chars[start] == '\'' || chars[start] == '"') {
- start = captureStringLiteral(chars[start], chars, start, end);
- }
- else if (chars[start] == type) {
- depth++;
- }
- else if (chars[start] == term && --depth == 0) {
- return start;
- }
- }
- }
- switch (type) {
- case '[':
- throw new CompileException("unbalanced braces [ ... ]", chars, start);
- case '{':
- throw new CompileException("unbalanced braces { ... }", chars, start);
- case '(':
- throw new CompileException("unbalanced braces ( ... )", chars, start);
- default:
- throw new CompileException("unterminated string literal", chars, start);
- }
- }
- public static int balancedCaptureWithLineAccounting(char[] chars, int start, int end, char type, ParserContext pCtx) {
- int depth = 1;
- int st = start;
- char term = type;
- switch (type) {
- case '[':
- term = ']';
- break;
- case '{':
- term = '}';
- break;
- case '(':
- term = ')';
- break;
- }
- if (type == term) {
- for (start++; start != end; start++) {
- if (chars[start] == type) {
- return start;
- }
- }
- }
- else {
- int lines = 0;
- for (start++; start < end; start++) {
- if (isWhitespace(chars[start])) {
- switch (chars[start]) {
- case '\r':
- continue;
- case '\n':
- if (pCtx != null) pCtx.setLineOffset((short) start);
- lines++;
- }
- }
- else if (start < end && chars[start] == '/') {
- if (start + 1 == end) return start;
- if (chars[start + 1] == '/') {
- start++;
- while (start < end && chars[start] != '\n') start++;
- }
- else if (chars[start + 1] == '*') {
- start += 2;
- Skiploop:
- while (start != end) {
- switch (chars[start]) {
- case '*':
- if (start + 1 < end && chars[start + 1] == '/') {
- break Skiploop;
- }
- case '\r':
- case '\n':
- if (pCtx != null) pCtx.setLineOffset((short) start);
- lines++;
- break;
- }
- start++;
- }
- }
- }
- if (start == end) return start;
- if (chars[start] == '\'' || chars[start] == '"') {
- start = captureStringLiteral(chars[start], chars, start, end);
- }
- else if (chars[start] == type) {
- depth++;
- }
- else if (chars[start] == term && --depth == 0) {
- if (pCtx != null) pCtx.incrementLineCount(lines);
- return start;
- }
- }
- }
- switch (type) {
- case '[':
- throw new CompileException("unbalanced braces [ ... ]", chars, st);
- case '{':
- throw new CompileException("unbalanced braces { ... }", chars, st);
- case '(':
- throw new CompileException("unbalanced braces ( ... )", chars, st);
- default:
- throw new CompileException("unterminated string literal", chars, st);
- }
- }
- public static String handleStringEscapes(char[] input) {
- int escapes = 0;
- for (int i = 0; i < input.length; i++) {
- if (input[i] == '\\') {
- escapes += handleEscapeSequence(input, ++i);
- }
- }
- if (escapes == 0) return new String(input);
- char[] processedEscapeString = new char[input.length - escapes];
- int cursor = 0;
- for (char aName : input) {
- if (aName != 0) {
- processedEscapeString[cursor++] = aName;
- }
- }
- return new String(processedEscapeString);
- }
- public static int captureStringLiteral(final char type, final char[] expr, int cursor, int end) {
- while (++cursor < end && expr[cursor] != type) {
- if (expr[cursor] == '\\') cursor++;
- }
- if (cursor >= end || expr[cursor] != type) {
- throw new CompileException("unterminated string literal", expr, cursor);
- }
- return cursor;
- }
- public static void parseWithExpressions(String nestParm,
- char[] block,
- int start,
- int offset,
- Object ctx,
- VariableResolverFactory factory) {
- /**
- *
- * MAINTENANCE NOTE: A COMPILING VERSION OF THIS CODE IS DUPLICATED IN: WithNode
- *
- */
- int _st = start;
- int _end = -1;
- int end = start + offset;
- int oper = -1;
- String parm = "";
- for (int i = start; i < end; i++) {
- switch (block[i]) {
- case '{':
- case '[':
- case '(':
- case '\'':
- case '"':
- i = balancedCapture(block, i, end, block[i]);
- continue;
- case '/':
- if (i < end && block[i + 1] == '/') {
- while (i < end && block[i] != '\n') block[i++] = ' ';
- if (parm == null) _st = i;
- }
- else if (i < end && block[i + 1] == '*') {
- int len = end - 1;
- while (i < len && !(block[i] == '*' && block[i + 1] == '/')) {
- block[i++] = ' ';
- }
- block[i++] = ' ';
- block[i++] = ' ';
- if (parm == null) _st = i;
- }
- else if (i < end && block[i + 1] == '=') {
- oper = Operator.DIV;
- }
- continue;
- case '%':
- case '*':
- case '-':
- case '+':
- if (i + 1 < end && block[i + 1] == '=') {
- oper = opLookup(block[i]);
- }
- continue;
- case '=':
- parm = new String(block, _st, i - _st - (oper != -1 ? 1 : 0)).trim();
- _st = i + 1;
- continue;
- case ',':
- if (_end == -1) _end = i;
- if (parm == null) {
- try {
- if (nestParm == null) {
- MVEL.eval(new String(block, _st, _end - _st), ctx, factory);
- }
- else {
- MVEL.eval(new StringBuilder(nestParm).append('.')
- .append(block, _st, _end - _st).toString(), ctx, factory);
- }
- }
- catch (CompileException e) {
- e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
- e.setExpr(block);
- throw e;
- }
- oper = -1;
- _st = ++i;
- }
- else {
- try {
- if (oper != -1) {
- if (nestParm == null) {
- throw new CompileException("operative assignment no…
Large files files are truncated, but you can click here to view the full file