All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mvel.util.ParseTools Maven / Gradle / Ivy

The newest version!
/**
 * MVEL (The MVFLEX Expression Language)
 *
 * Copyright (C) 2007 Christopher Brock, MVFLEX/Valhalla Project and the Codehaus
 *
 * 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.mvel.util;

import org.mvel.*;
import static org.mvel.DataConversion.canConvert;
import static org.mvel.MVEL.getDebuggingOutputFileName;
import org.mvel.ast.ASTNode;
import static org.mvel.compiler.AbstractParser.*;
import org.mvel.compiler.*;
import org.mvel.integration.ResolverTools;
import static org.mvel.integration.ResolverTools.insertFactory;
import org.mvel.integration.VariableResolverFactory;
import org.mvel.integration.impl.ClassImportResolverFactory;
import org.mvel.integration.impl.StaticMethodImportResolverFactory;
import org.mvel.integration.impl.TypeInjectionResolverFactoryImpl;
import org.mvel.math.MathProcessor;
import static org.mvel.util.PropertyTools.createStringTrimmed;
import sun.misc.Unsafe;

import java.io.*;
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 java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import static java.nio.ByteBuffer.allocateDirect;
import java.nio.channels.ReadableByteChannel;
import java.util.*;


/**
 * This class contains much of the actual parsing code used by the core parser.
 */
@SuppressWarnings({"ManualArrayCopy"})
public class ParseTools {
    public static final Object[] EMPTY_OBJ_ARR = new Object[0];
    public static final MathProcessor MATH_PROCESSOR;
    public static final boolean JDK_14_COMPATIBILITY;

    static {
        try {
            double version = parseDouble(System.getProperty("java.version").substring(0, 3));
            if (version == 1.4) {
                MATH_PROCESSOR = (MathProcessor) forName("org.mvel.math.JDK14CompatabilityMath").newInstance();
                JDK_14_COMPATIBILITY = true;
            }
            else if (version > 1.4) {
                MATH_PROCESSOR = (MathProcessor) forName("org.mvel.math.IEEEFloatingPointMath").newInstance();
                JDK_14_COMPATIBILITY = false;
            }
            else {
                throw new RuntimeException("unsupported java version: " + version);
            }
        }
        catch (RuntimeException e) {
            throw e;
        }
        catch (Exception e) {
            throw new RuntimeException("unable to initialize math processor", e);
        }

    }

    public static String[] parseMethodOrConstructor(char[] parm) {
        int start = -1;
        for (int i = 0; i < parm.length; i++) {
            if (parm[i] == '(') {
                start = ++i;
                break;
            }
        }
        if (start != -1) {
            start--;
            return parseParameterList(parm, start + 1, balancedCapture(parm, start, '(') - start - 1);
        }

        return null;
    }

    public static String[] getMethodNameAndParms(char[] parm) {
        int start = -1;
        String methName = null;

        for (int i = 0; i < parm.length; i++) {
            if (parm[i] == '(') {
                methName = new String(parm, 0, i);

                start = ++i;
                break;
            }
        }
        if (start != -1) {
            start--;
            String[] parms = parseParameterList(parm, start + 1, balancedCapture(parm, start, '(') - start - 1);
            String[] nArray = new String[parms.length + 1];
            nArray[0] = methName;

            for (int i = 0; i < parms.length; i++) {
                nArray[i + 1] = parms[i];
            }

            return nArray;
        }

        return null;


    }

    public static String[] parseParameterList(char[] parm, int offset, int length) {
        List list = new LinkedList();

        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(new String(parm, start, i - start));
                    }

                    while (isWhitespace(parm[i]))
                        i++;

                    start = i + 1;
            }
        }

        if (start < (length + offset) && i > start) {
            String s = createStringTrimmed(parm, start, i - start);
            if (s.length() > 0)
                list.add(s);
        }
        else if (list.size() == 0) {
            String s = createStringTrimmed(parm, start, length);
            if (s.length() > 0)
                list.add(s);
        }

        return list.toArray(new String[list.size()]);
    }

    private static Map> RESOLVED_METH_CACHE = new WeakHashMap>(10);

    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) {
        if (methods.length == 0) {
            return null;
        }
        Class[] parmTypes;
        Method bestCandidate = null;
        int bestScore = 0;
        int score = 0;

        Integer hash = createClassSignatureHash(decl, arguments);

        Map methCache = RESOLVED_METH_CACHE.get(method);
        if (methCache != null) {
            if ((bestCandidate = methCache.get(hash)) != null) return bestCandidate;
        }

        for (Method meth : methods) {
            if (method.equals(meth.getName())) {
                if ((parmTypes = meth.getParameterTypes()).length != arguments.length)
                    continue;
                else if (arguments.length == 0 && parmTypes.length == 0) {
                    bestCandidate = meth;
                    break;
                }

                for (int i = 0; i < arguments.length; i++) {
                    if (arguments[i] == null) {
                        if (!parmTypes[i].isPrimitive()) {
                            score += 5;
                        }
                        else {
                            score = 0;
                            break;
                        }
                    }
                    else if (parmTypes[i] == arguments[i]) {
                        score += 5;
                    }
                    else if (parmTypes[i].isPrimitive() && boxPrimitive(parmTypes[i]) == arguments[i]) {
                        score += 4;
                    }
                    else if (arguments[i].isPrimitive() && unboxPrimitive(arguments[i]) == parmTypes[i]) {
                        score += 4;
                    }
                    else if (isNumericallyCoercible(arguments[i], parmTypes[i])) {
                        score += 3;
                    }
                    else if (parmTypes[i].isAssignableFrom(arguments[i])) {
                        score += 2;
                    }
                    else if (!requireExact && canConvert(parmTypes[i], arguments[i])) {
                        if (parmTypes[i].isArray() && arguments[i].isArray()) score += 1;
                        score += 1;
                    }
                    else if (arguments[i] == Object.class) {
                        score += 1;
                    }
                    else {
                        score = 0;
                        break;
                    }
                }


                if (score != 0 && score > bestScore) {
                    bestCandidate = meth;
                    bestScore = score;
                }
                score = 0;
            }
        }

        if (bestCandidate != null) {
            //        methCache = RESOLVED_METH_CACHE.get(method);
            if (methCache == null) {
                RESOLVED_METH_CACHE.put(method, methCache = new WeakHashMap());
            }

            methCache.put(hash, bestCandidate);
        }

        return bestCandidate;
    }

    public static Method getExactMatch(String name, Class[] args, Class returnType, Class cls) {
        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]) return null;
                }
                return meth;
            }
        }
        return null;
    }

    public static Method getWidenedTarget(Method method) {
        Class cls = method.getDeclaringClass();
        Method m = method, best = method;
        Class[] args = method.getParameterTypes();
        String name = method.getName();
        Class rt = m.getReturnType();

        do {
            for (Class iface : cls.getInterfaces()) {
                if ((m = getExactMatch(name, args, rt, iface)) != null) {
                    if ((best = m).getDeclaringClass().getSuperclass() != null) {
                        cls = m.getDeclaringClass();
                    }
                }
            }
        }
        while ((cls = cls.getSuperclass()) != null);

        return best;
    }

    private static Map> RESOLVED_CONST_CACHE = new WeakHashMap>(10);
    private static Map CONSTRUCTOR_PARMS_CACHE = new WeakHashMap(10);

    private static Class[] getConstructors(Constructor cns) {
        Class[] parms = CONSTRUCTOR_PARMS_CACHE.get(cns);
        if (parms != null)
            return parms;
        else {
            parms = cns.getParameterTypes();
            CONSTRUCTOR_PARMS_CACHE.put(cns, parms);
            return parms;
        }
    }

    public static Constructor getBestConstructorCanadidate(Object[] arguments, Class cls) {
        Class[] parmTypes;
        Constructor bestCandidate = null;
        int bestScore = 0;
        int score = 0;

        Class[] targetParms = new Class[arguments.length];

        for (int i = 0; i < arguments.length; i++) {
            if (arguments[i] != null) {
                targetParms[i] = arguments[i].getClass();
            }
        }
        Integer hash = createClassSignatureHash(cls, targetParms);

        Map cache = RESOLVED_CONST_CACHE.get(cls);
        if (cache != null) {
            if ((bestCandidate = cache.get(hash)) != null) return bestCandidate;
        }

        for (Constructor construct : getConstructors(cls)) {
            if ((parmTypes = getConstructors(construct)).length != arguments.length)
                continue;
            else if (arguments.length == 0 && parmTypes.length == 0)
                return construct;

            for (int i = 0; i < arguments.length; i++) {
                if (targetParms[i] == null) {
                    if (!parmTypes[i].isPrimitive()) score += 5;
                    else {
                        score = 0;
                        break;
                    }
                }
                else if (parmTypes[i] == targetParms[i]) {
                    score += 5;
                }
                else if (parmTypes[i].isPrimitive() && boxPrimitive(parmTypes[i]) == targetParms[i]) {
                    score += 4;
                }
                else if (targetParms[i].isPrimitive() && unboxPrimitive(targetParms[i]) == parmTypes[i]) {
                    score += 4;
                }
                else if (isNumericallyCoercible(targetParms[i], parmTypes[i])) {
                    score += 3;
                }
                else if (parmTypes[i].isAssignableFrom(targetParms[i])) {
                    score += 2;
                }
                else if (canConvert(parmTypes[i], targetParms[i])) {
                    score += 1;
                }
                else {
                    score = 0;
                    break;
                }
            }

            if (score != 0 && score > bestScore) {
                bestCandidate = construct;
                bestScore = score;
            }
            score = 0;

        }

        if (bestCandidate != null) {
            if (cache == null) {
                RESOLVED_CONST_CACHE.put(cls, cache = new WeakHashMap());
            }
            cache.put(hash, bestCandidate);
        }


        return bestCandidate;
    }


    private static Map> CLASS_RESOLVER_CACHE = new WeakHashMap>(1, 1.0f);
    private static Map CLASS_CONSTRUCTOR_CACHE = new WeakHashMap(10);

    public static Class createClassSafe(String className) {
        try {
            return createClass(className);
        }
        catch (ClassNotFoundException e) {
            return null;
        }
    }

    public static Class createClass(String className) throws ClassNotFoundException {
        ClassLoader classLoader = currentThread().getContextClassLoader();
        Map cache = CLASS_RESOLVER_CACHE.get(classLoader);
        if (cache == null) {
            CLASS_RESOLVER_CACHE.put(classLoader, cache = new WeakHashMap(10));
        }

        Class cls;

        if ((cls = cache.get(className)) != null) {
            return cls;
        }
        else {
            try {
                cls = currentThread().getContextClassLoader().loadClass(className);
            }
            catch (ClassNotFoundException e) {
                /**
                 * Now try the system classloader.
                 */
                cls = forName(className);
            }

            cache.put(className, cls);
            return cls;
        }
    }


    public static Constructor[] getConstructors(Class cls) {
        Constructor[] cns = CLASS_CONSTRUCTOR_CACHE.get(cls);
        if (cns != null) {
            return cns;
        }
        else {
            CLASS_CONSTRUCTOR_CACHE.put(cls, cns = cls.getConstructors());
            return cns;
        }
    }


    public static String[] captureContructorAndResidual(String token) {
        char[] cs = token.toCharArray();

        int depth = 0;

        for (int i = 0; i < cs.length; i++) {
            switch (cs[i]) {
                case '(':
                    depth++;
                    continue;
                case ')':
                    if (1 == depth--) {
                        return new String[]{new String(cs, 0, ++i), new String(cs, i, cs.length - i)};
                    }
            }
        }
        return new String[]{token};
    }

    public static String[] captureContructorAndResidual(char[] cs) {
        int depth = 0;
        for (int i = 0; i < cs.length; i++) {
            switch (cs[i]) {
                case '(':
                    depth++;
                    continue;
                case ')':
                    if (1 == depth--) {
                        return new String[]{new String(cs, 0, ++i), createStringTrimmed(cs, i, cs.length - i)};
                    }
            }
        }
        return new String[]{new String(cs)};
    }

    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 == 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 null;
    }

    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 == 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)
            // @todo use String.contains once we move to jdk1.5
            return ((String) compareTo).indexOf(valueOf(compareTest)) > -1;
        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()) {
            for (Object o : ((Object[]) compareTo)) {
                if (compareTest == null && o == null)
                    return true;
                else if ((Boolean) doOperations(o, Operator.EQUAL, compareTest))
                    return true;
            }
        }
        return false;
    }

    public static int createClassSignatureHash(Class declaring, Class[] sig) {
        int hash = 0;
        for (Class cls : sig) {
            if (cls != null)
                hash += cls.hashCode();
        }

        return hash + sig.length + declaring.hashCode();
    }

    public static char handleEscapeSequence(char escapedChar) {
        switch (escapedChar) {
            case '\\':
                return '\\';
            case 't':
                return '\t';
            case 'r':
                return '\r';
            case 'n':
                return '\n';
            case '\'':
                return '\'';
            case '"':
                return '"';
            default:
                throw new ParseException("illegal escape sequence: " + escapedChar);
        }
    }

    public static char[] createShortFormOperativeAssignment(String name, char[] statement, 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.DIV:
                op = '/';
                break;
            case Operator.BW_AND:
                op = '&';
                break;
            case Operator.BW_OR:
                op = '|';
                break;
        }

        arraycopy(name.toCharArray(), 0, (stmt = new char[name.length() + statement.length + 1]), 0, name.length());
        stmt[name.length()] = op;
        arraycopy(statement, 0, stmt, name.length() + 1, statement.length);

        return stmt;
    }


    public static TypeInjectionResolverFactoryImpl findTypeInjectionResolverFactory(VariableResolverFactory factory) {
        VariableResolverFactory v = factory;
        while (v != null) {
            if (v instanceof TypeInjectionResolverFactoryImpl) {
                return (TypeInjectionResolverFactoryImpl) v;
            }
            v = v.getNextFactory();
        }

        if (factory == null) {
            throw new OptimizationFailure("unable to import classes.  no variable resolver factory available.");
        }
        else {
            return ResolverTools.appendFactory(factory, new TypeInjectionResolverFactoryImpl());
        }
    }


    public static ClassImportResolverFactory findClassImportResolverFactory(VariableResolverFactory factory) {
        VariableResolverFactory v = factory;
        while (v != null) {
            if (v instanceof ClassImportResolverFactory) {
                return (ClassImportResolverFactory) v;
            }
            v = v.getNextFactory();
        }

        if (factory == null) {
            throw new OptimizationFailure("unable to import classes.  no variable resolver factory available.");
        }
        else {
            return insertFactory(factory, new ClassImportResolverFactory());
        }
    }

    public static StaticMethodImportResolverFactory findStaticMethodImportResolverFactory(VariableResolverFactory factory) {
        VariableResolverFactory v = factory;
        while (v != null) {
            if (v instanceof StaticMethodImportResolverFactory) {
                return (StaticMethodImportResolverFactory) v;
            }
            v = v.getNextFactory();
        }

        if (factory == null) {
            throw new OptimizationFailure("unable to import classes.  no variable resolver factory available.");
        }
        else {
            return insertFactory(factory, new StaticMethodImportResolverFactory());
        }
    }

    public static Class findClass(VariableResolverFactory factory, String name) 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 (getCurrentThreadParserContext() != null && getCurrentThreadParserContext().hasImport(name)) {
                return getCurrentThreadParserContext().getImport(name);
            }
            else {
                return createClass(name);
            }
        }
        catch (ClassNotFoundException e) {
            throw e;
        }
        catch (Exception e) {
            throw new CompileException("class not found: " + name, e);
        }
    }

    public static boolean debug(String str) {
        return true;
    }

    public static boolean debug(Throwable t) {
        t.printStackTrace();
        return true;
    }

    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 Map typeResolveMap = new HashMap();

    static {
        Map 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, DataTypes.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, DataTypes.DOUBLE);
        t.put(Double.class, DataTypes.W_DOUBLE);

        t.put(long.class, DataTypes.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(Class cls) {
        Integer i = typeResolveMap.get(cls);
        if (i == null) return DataTypes.OBJECT;
        else {
            return i;
        }
    }

    public static int __resolveType(Class cls) {
        if (cls == null)
            return 0;
        if (BigDecimal.class == cls)
            return DataTypes.BIG_DECIMAL;

        if (BigInteger.class == cls)
            return DataTypes.BIG_INTEGER;

        if (String.class == cls)
            return DataTypes.STRING;

        if (int.class == cls)
            return DataTypes.INTEGER;
        if (short.class == cls)
            return DataTypes.SHORT;
        if (float.class == cls)
            return DataTypes.FLOAT;
        if (double.class == cls)
            return DataTypes.DOUBLE;
        if (long.class == cls)
            return DataTypes.LONG;
        if (boolean.class == cls)
            return DataTypes.BOOLEAN;
        if (byte.class == cls)
            return DataTypes.BYTE;
        if (char.class == cls)
            return DataTypes.CHAR;


        if (Integer.class == cls)
            return DataTypes.W_INTEGER;
        if (Short.class == cls)
            return DataTypes.W_SHORT;
        if (Float.class == cls)
            return DataTypes.W_FLOAT;
        if (Double.class == cls)
            return DataTypes.W_DOUBLE;
        if (Long.class == cls)
            return DataTypes.W_LONG;
        if (Boolean.class == cls)
            return DataTypes.W_BOOLEAN;
        if (Byte.class == cls)
            return DataTypes.W_BYTE;
        if (Character.class == cls)
            return DataTypes.W_CHAR;

        if (BlankLiteral.class == cls)
            return DataTypes.EMPTY;

        if (Unit.class.isAssignableFrom(cls))
            return DataTypes.UNIT;

        return DataTypes.OBJECT;
    }

    public static Object valueOnly(Object o) {
        return (o instanceof ASTNode) ? ((ASTNode) o).getLiteralValue() : o;
    }

    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 handleParserEgress(Object result, boolean returnBigDecimal) {
        if (result instanceof BigDecimal) {
            int scale = ((BigDecimal) result).scale();

            if (returnBigDecimal) return result;
            else if (scale > 0) {
                return ((BigDecimal) result).doubleValue();
            }
            else if (((BigDecimal) result).longValue() > Integer.MAX_VALUE) {
                return ((BigDecimal) result).longValue();
            }
            else {
                return ((BigDecimal) result).intValue();
            }
        }
        else {
            return result;
        }
    }

    public static Method determineActualTargetMethod(Method method) {
        String name = method.getName();

        /**
         * Follow our way up the class heirarchy until we find the physical target method.
         */
        for (Class cls : method.getDeclaringClass().getInterfaces()) {
            for (Method meth : cls.getMethods()) {
                if (meth.getParameterTypes().length == 0 && name.equals(meth.getName())) {
                    return meth;
                }
            }
        }

        return null;
    }

    public static Object doOperations(Object val1, int operation, Object val2) {
        return MATH_PROCESSOR.doOperation(val1, operation, val2);
    }

    public static Object increment(Object o) {
        if (o instanceof Integer) {
            return (Integer) o + 1;
        }
        else if (o instanceof Double) {
            return (Double) o + 1;
        }
        else if (o instanceof Float) {
            return (Float) o + 1;
        }
        else if (o instanceof Short) {
            return (Short) o + 1;
        }
        else if (o instanceof Character) {
            return (Character) o + 1;
        }
        else {
            throw new CompileException("unable to increment type: " + (o != null ? o.getClass().getName() : "null"));
        }
    }


    public static Map parseParameters(char[] parms) {
        Map allParms = new HashMap();

        boolean capture = false;
        int start = 0;

        String parmName = null;
        int i = 0;
        for (; i < parms.length; i++) {
            switch (parms[i]) {
                case '=':
                    parmName = createStringTrimmed(parms, start, ++i - start - 1);
                    capture = true;
                    start = i;
                    break;

                case ',':
                    if (capture) {
                        allParms.put(parmName, createStringTrimmed(parms, start, i - start));
                        start = ++i;
                        capture = false;
                        break;
                    }
            }
        }

        if (capture) {
            allParms.put(parmName, createStringTrimmed(parms, start, i - start));
        }

        return allParms;
    }

    /**
     * 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:
     * ( [ { ' " 
     * 
*
* For example: ((foo + bar + (bar - foo)) * 20;
*
*

* If a balanced capture is performed from position 2, we get "(foo + bar + (bar - foo))" back.
* If a balanced capture is performed from position 15, we get "(bar - foo)" back.
* Etc. * * @param chars - * @param start - * @param type - * @return - */ public static int balancedCapture(char[] chars, int start, 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 < chars.length; start++) { if (chars[start] == type) { return start; } } } else { for (start++; start < chars.length; start++) { if (chars[start] == '/' && start < chars.length) { if (chars[start + 1] == '/') { start++; while (start < chars.length && chars[start] != '\n') start++; } else if (chars[start + 1] == '*') { start += 2; while (start < chars.length) { switch (chars[start]) { case '*': if (start < chars.length && chars[start + 1] == '/') { break; } case '\r': case '\n': } } } } if (chars[start] == '\'' || chars[start] == '"') { start = captureStringLiteral(chars[start], chars, start, chars.length); } 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, 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 < chars.length; start++) { if (chars[start] == type) { return new int[]{start, 0}; } } } else { int lines = 0; for (start++; start < chars.length; start++) { if (isWhitespace(chars[start])) { switch (chars[start]) { case '\r': continue; case '\n': lines++; } } else if (chars[start] == '/' && start < chars.length) { if (chars[start + 1] == '/') { start++; while (start < chars.length && chars[start] != '\n') start++; } else if (chars[start + 1] == '*') { start += 2; while (start < chars.length) { switch (chars[start]) { case '*': if (start < chars.length && chars[start + 1] == '/') { break; } case '\r': continue; case '\n': lines++; } } } } else if (chars[start] == '\'' || chars[start] == '"') { start = captureStringLiteral(chars[start], chars, start, chars.length); } else if (chars[start] == type) { depth++; } else if (chars[start] == term && --depth == 0) { return new int[]{start, lines}; } } } 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 String handleStringEscapes(char[] input) { int escapes = 0; for (int i = 0; i < input.length; i++) { if (input[i] == '\\') { input[i++] = 0; input[i] = handleEscapeSequence(input[i]); escapes++; } } char[] processedEscapeString = new char[input.length - escapes]; int cursor = 0; for (char aName : input) { if (aName == 0) { continue; } processedEscapeString[cursor++] = aName; } return new String(processedEscapeString); } public static int captureStringLiteral(final char type, final char[] expr, int cursor, int length) { while (++cursor < length && expr[cursor] != type) { if (expr[cursor] == '\\') handleEscapeSequence(expr[++cursor]); } if (cursor == length || expr[cursor] != type) { throw new CompileException("unterminated literal", expr, cursor); } return cursor; } public static WithStatementPair[] parseWithExpressions(String nestParm, char[] block) { List parms = new ArrayList(); int start = 0; String parm = ""; int end = -1; int oper = -1; for (int i = 0; i < block.length; i++) { switch (block[i]) { case '{': case '[': case '(': i = balancedCapture(block, i, block[i]); continue; case '*': if (i < block.length && block[i + 1] == '=') { oper = Operator.MULT; } continue; case '/': if (i < block.length && block[i + 1] == '/') { end = i; while (i < block.length && block[i] != '\n') i++; if (parm == null) start = i; } else if (i < block.length && block[i + 1] == '*') { end = i; while (i < block.length) { switch (block[i++]) { case '*': if (i < block.length) { if (block[i] == '/') break; } } } if (parm == null) start = i; } else if (i < block.length && block[i + 1] == '=') { oper = Operator.DIV; } continue; case '-': if (i < block.length && block[i + 1] == '=') { oper = Operator.SUB; } continue; case '+': if (i < block.length && block[i + 1] == '=') { oper = Operator.ADD; } continue; case '=': parm = createStringTrimmed(block, start, i - start - (oper != -1 ? 1 : 0)); start = ++i; continue; case ',': if (end == -1) end = i; if (parm == null) { parms.add( new WithStatementPair(null, new StringAppender(nestParm).append('.') .append(subset(block, start, end - start)).toString()) ); oper = -1; start = ++i; } else { parms.add(new WithStatementPair(parm, new String(createShortFormOperativeAssignment(nestParm + "." + parm, subset(block, start, end - start), oper)))); parm = null; oper = -1; start = ++i; } end = -1; break; } } if (start != (end = block.length)) { if (parm == null) { parms.add(new WithStatementPair(null, new StringAppender(nestParm).append('.') .append(subset(block, start, end - start)).toString())); } else { parms.add(new WithStatementPair( parm, new String(createShortFormOperativeAssignment(nestParm + "." + parm, subset(block, start, end - start), oper)) )); } } WithStatementPair[] ret; parms.toArray(ret = new WithStatementPair[parms.size()]); return ret; } public static final class WithStatementPair implements java.io.Serializable { private String parm; private String value; public WithStatementPair(String parm, String value) { this.parm = parm; this.value = value; } public String getParm() { return parm; } public void setParm(String parm) { this.parm = parm; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } /** * REMOVE THIS WITH JDK1.4 COMPATIBILITY! COMPENSATES FOR LACK OF getSimpleName IN java.lang.Class -- DIE 1.4! * * @param cls -- class reference * @return Simple name of class */ public static String getSimpleClassName(Class cls) { if (JDK_14_COMPATIBILITY) { int lastIndex = cls.getName().lastIndexOf('$'); if (lastIndex < 0) { lastIndex = cls.getName().lastIndexOf('.'); } if (cls.isArray()) { return cls.getName().substring(lastIndex + 1) + "[]"; } else { return cls.getName().substring(lastIndex + 1); } } else { return cls.getSimpleName(); } } public static void checkNameSafety(String name) { if (isReservedWord(name)) { throw new CompileException("illegal use of reserved word: " + name); } } public static FileWriter getDebugFileWriter() throws IOException { return new FileWriter(new File(getDebuggingOutputFileName()), true); } public static boolean isPrimitiveWrapper(Class clazz) { return clazz == Integer.class || clazz == Boolean.class || clazz == Long.class || clazz == Double.class || clazz == Float.class || clazz == Short.class || clazz == Byte.class || clazz == Character.class; } public static Serializable subCompileExpression(String expression) { return optimizeTree(new ExpressionCompiler(expression)._compile()); } public static Serializable subCompileExpression(char[] expression) { return optimizeTree(new ExpressionCompiler(expression)._compile()); } public static Serializable subCompileExpression(char[] expression, ParserContext ctx) { return optimizeTree(new ExpressionCompiler(expression, ctx)._compile()); } public static Serializable subCompileExpression(String expression, ParserContext ctx) { return optimizeTree(new ExpressionCompiler(expression, ctx)._compile()); } public static Serializable optimizeTree(final CompiledExpression compiled) { ASTIterator nodes = compiled.getInstructions(); /** * If there is only one token, and it's an identifier, we can optimize this as an accessor expression. */ if (MVEL.isOptimizationEnabled() && nodes.size() == 1) { ASTNode tk = nodes.firstNode(); if (tk.isLiteral() && !tk.isThisVal()) { if ((tk.getFields() & ASTNode.INTEGER32) != 0) { return new ExecutableLiteral(tk.getIntRegister()); } else { return new ExecutableLiteral(tk.getLiteralValue()); } } return tk.canSerializeAccessor() ? new ExecutableAccessorSafe(tk, false, compiled.getKnownEgressType()) : new ExecutableAccessor(tk, false, compiled.getKnownEgressType()); } return compiled; } public static boolean isWhitespace(char c) { return c <= '\u0020'; } public static String repeatChar(char c, int times) { char[] n = new char[times]; for (int i = 0; i < times; i++) { n[i] = c; } return new String(n); } public static char[] loadFromFile(File file) throws IOException { if (!file.exists()) throw new CompileException("cannot find file: " + file.getName()); FileInputStream inStream = null; ReadableByteChannel fc = null; try { fc = (inStream = new FileInputStream(file)).getChannel(); ByteBuffer buf = allocateDirect(10); StringAppender sb = new StringAppender((int) file.length()); int read = 0; while (read >= 0) { buf.rewind(); read = fc.read(buf); buf.rewind(); for (; read > 0; read--) { sb.append((char) buf.get()); } } //noinspection unchecked return sb.toChars(); } catch (FileNotFoundException e) { // this can't be thrown, we check for this explicitly. } finally { if (inStream != null) inStream.close(); if (fc != null) fc.close(); } return null; } private static Unsafe _getUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(null); } catch (Exception ex) { throw new RuntimeException("can't get Unsafe instance", ex); } } private static final Unsafe unsafe__ = _getUnsafe(); public static Unsafe getUnsafe() { return unsafe__; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy