0001: /**
0002: * MVEL (The MVFLEX Expression Language)
0003: *
0004: * Copyright (C) 2007 Christopher Brock, MVFLEX/Valhalla Project and the Codehaus
0005: *
0006: * Licensed under the Apache License, Version 2.0 (the "License");
0007: * you may not use this file except in compliance with the License.
0008: * You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing, software
0013: * distributed under the License is distributed on an "AS IS" BASIS,
0014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: *
0018: */package org.mvel.util;
0019:
0020: import org.mvel.*;
0021: import static org.mvel.DataConversion.canConvert;
0022: import org.mvel.ast.ASTNode;
0023: import org.mvel.compiler.*;
0024: import static org.mvel.compiler.AbstractParser.getCurrentThreadParserContext;
0025: import static org.mvel.compiler.AbstractParser.isReservedWord;
0026: import org.mvel.integration.ResolverTools;
0027: import org.mvel.integration.VariableResolverFactory;
0028: import org.mvel.integration.impl.ClassImportResolverFactory;
0029: import org.mvel.integration.impl.StaticMethodImportResolverFactory;
0030: import org.mvel.integration.impl.TypeInjectionResolverFactoryImpl;
0031: import org.mvel.math.MathProcessor;
0032: import sun.misc.Unsafe;
0033:
0034: import java.io.*;
0035: import static java.lang.Character.isWhitespace;
0036: import static java.lang.Double.parseDouble;
0037: import static java.lang.String.valueOf;
0038: import static java.lang.System.arraycopy;
0039: import static java.lang.Thread.currentThread;
0040: import java.lang.reflect.Constructor;
0041: import java.lang.reflect.Field;
0042: import java.lang.reflect.Method;
0043: import java.math.BigDecimal;
0044: import java.math.BigInteger;
0045: import java.nio.ByteBuffer;
0046: import static java.nio.ByteBuffer.allocateDirect;
0047: import java.nio.channels.ReadableByteChannel;
0048: import java.util.*;
0049:
0050: /**
0051: * This class contains much of the actual parsing code used by the core parser.
0052: */
0053: @SuppressWarnings({"ManualArrayCopy"})
0054: public class ParseTools {
0055: public static final Object[] EMPTY_OBJ_ARR = new Object[0];
0056: public static final MathProcessor MATH_PROCESSOR;
0057: public static final boolean JDK_14_COMPATIBILITY;
0058:
0059: static {
0060: try {
0061: double version = parseDouble(System.getProperty(
0062: "java.version").substring(0, 3));
0063: if (version == 1.4) {
0064: MATH_PROCESSOR = (MathProcessor) currentThread()
0065: .getContextClassLoader().loadClass(
0066: "org.mvel.math.JDK14CompatabilityMath")
0067: .newInstance();
0068: JDK_14_COMPATIBILITY = true;
0069: } else if (version > 1.4) {
0070: MATH_PROCESSOR = (MathProcessor) currentThread()
0071: .getContextClassLoader().loadClass(
0072: "org.mvel.math.IEEEFloatingPointMath")
0073: .newInstance();
0074: JDK_14_COMPATIBILITY = false;
0075: } else {
0076: throw new RuntimeException("unsupported java version: "
0077: + version);
0078: }
0079: } catch (RuntimeException e) {
0080: throw e;
0081: } catch (Exception e) {
0082: throw new RuntimeException(
0083: "unable to initialize math processor", e);
0084: }
0085:
0086: }
0087:
0088: public static String[] parseMethodOrConstructor(char[] parm) {
0089: int start = -1;
0090: for (int i = 0; i < parm.length; i++) {
0091: if (parm[i] == '(') {
0092: start = ++i;
0093: break;
0094: }
0095: }
0096: if (start != -1) {
0097: start--;
0098: return parseParameterList(parm, start + 1, balancedCapture(
0099: parm, start, '(')
0100: - start - 1);
0101: }
0102:
0103: return null;
0104: }
0105:
0106: public static String[] parseParameterList(char[] parm, int offset,
0107: int length) {
0108: List<String> list = new LinkedList<String>();
0109:
0110: if (length == -1)
0111: length = parm.length;
0112:
0113: int start = offset;
0114: int i = offset;
0115: int end = i + length;
0116:
0117: for (; i < end; i++) {
0118: switch (parm[i]) {
0119: case '(':
0120: case '[':
0121: case '{':
0122: i = balancedCapture(parm, i, parm[i]);
0123: continue;
0124:
0125: case '\'':
0126: i = captureStringLiteral('\'', parm, i, parm.length);
0127: continue;
0128:
0129: case '"':
0130: i = captureStringLiteral('"', parm, i, parm.length);
0131: continue;
0132:
0133: case ',':
0134: if (i > start) {
0135: while (isWhitespace(parm[start]))
0136: start++;
0137:
0138: list.add(new String(parm, start, i - start));
0139: }
0140:
0141: while (isWhitespace(parm[i]))
0142: i++;
0143:
0144: start = i + 1;
0145: }
0146: }
0147:
0148: if (start < (length + offset) && i > start) {
0149: String s = new String(parm, start, i - start).trim();
0150: if (s.length() > 0)
0151: list.add(s);
0152: } else if (list.size() == 0) {
0153: String s = new String(parm, start, length).trim();
0154: if (s.length() > 0)
0155: list.add(s);
0156: }
0157:
0158: return list.toArray(new String[list.size()]);
0159: }
0160:
0161: private static Map<String, Map<Integer, Method>> RESOLVED_METH_CACHE = new WeakHashMap<String, Map<Integer, Method>>(
0162: 10);
0163:
0164: public static Method getBestCandidate(Object[] arguments,
0165: String method, Class decl, Method[] methods) {
0166: Class[] targetParms = new Class[arguments.length];
0167: for (int i = 0; i < arguments.length; i++) {
0168: targetParms[i] = arguments[i] != null ? arguments[i]
0169: .getClass() : null;
0170: }
0171: return getBestCandidate(targetParms, method, decl, methods);
0172: }
0173:
0174: public static Method getBestCandidate(Class[] arguments,
0175: String method, Class decl, Method[] methods) {
0176: if (methods.length == 0) {
0177: return null;
0178: }
0179: Class[] parmTypes;
0180: Method bestCandidate = null;
0181: int bestScore = 0;
0182: int score = 0;
0183:
0184: Integer hash = createClassSignatureHash(decl, arguments);
0185:
0186: Map<Integer, Method> methCache = RESOLVED_METH_CACHE
0187: .get(method);
0188: if (methCache != null) {
0189: if ((bestCandidate = methCache.get(hash)) != null)
0190: return bestCandidate;
0191: }
0192:
0193: for (Method meth : methods) {
0194: if (method.equals(meth.getName())) {
0195: if ((parmTypes = meth.getParameterTypes()).length != arguments.length)
0196: continue;
0197: else if (arguments.length == 0 && parmTypes.length == 0) {
0198: bestCandidate = meth;
0199: break;
0200: }
0201:
0202: for (int i = 0; i < arguments.length; i++) {
0203: if (arguments[i] == null) {
0204: if (!parmTypes[i].isPrimitive()) {
0205: score += 5;
0206: } else {
0207: score = 0;
0208: break;
0209: }
0210: } else if (parmTypes[i] == arguments[i]) {
0211: score += 5;
0212: } else if (parmTypes[i].isPrimitive()
0213: && boxPrimitive(parmTypes[i]) == arguments[i]) {
0214: score += 4;
0215: } else if (arguments[i].isPrimitive()
0216: && unboxPrimitive(arguments[i]) == parmTypes[i]) {
0217: score += 4;
0218: } else if (isNumericallyCoercible(arguments[i],
0219: parmTypes[i])) {
0220: score += 3;
0221: } else if (parmTypes[i]
0222: .isAssignableFrom(arguments[i])) {
0223: score += 2;
0224: } else if (canConvert(parmTypes[i], arguments[i])
0225: || arguments[i] == Object.class) {
0226: score += 1;
0227: } else {
0228: score = 0;
0229: break;
0230: }
0231: }
0232:
0233: if (score != 0 && score > bestScore) {
0234: bestCandidate = meth;
0235: bestScore = score;
0236: }
0237: score = 0;
0238: }
0239: }
0240:
0241: if (bestCandidate != null) {
0242: // methCache = RESOLVED_METH_CACHE.get(method);
0243: if (methCache == null) {
0244: RESOLVED_METH_CACHE.put(method,
0245: methCache = new WeakHashMap<Integer, Method>());
0246: }
0247:
0248: methCache.put(hash, bestCandidate);
0249: }
0250:
0251: return bestCandidate;
0252: }
0253:
0254: public static Method getExactMatch(String name, Class[] args,
0255: Class returnType, Class cls) {
0256: for (Method meth : cls.getMethods()) {
0257: if (name.equals(meth.getName())
0258: && returnType == meth.getReturnType()) {
0259: Class[] parameterTypes = meth.getParameterTypes();
0260: if (parameterTypes.length != args.length)
0261: continue;
0262:
0263: for (int i = 0; i < parameterTypes.length; i++) {
0264: if (parameterTypes[i] != args[i])
0265: return null;
0266: }
0267: return meth;
0268: }
0269: }
0270: return null;
0271: }
0272:
0273: public static Method getWidenedTarget(Method method) {
0274: Class cls = method.getDeclaringClass();
0275: Method m = method;
0276: Class[] args = method.getParameterTypes();
0277: String name = method.getName();
0278: Class rt = m.getReturnType();
0279:
0280: do {
0281: for (Class iface : cls.getInterfaces()) {
0282: if ((m = getExactMatch(name, args, rt, iface)) != null
0283: && m.getDeclaringClass().getSuperclass() != null) {
0284: cls = m.getDeclaringClass();
0285: }
0286: }
0287: } while ((cls = cls.getSuperclass()) != null);
0288:
0289: return m != null ? m : method;
0290: }
0291:
0292: private static Map<Class, Map<Integer, Constructor>> RESOLVED_CONST_CACHE = new WeakHashMap<Class, Map<Integer, Constructor>>(
0293: 10);
0294: private static Map<Constructor, Class[]> CONSTRUCTOR_PARMS_CACHE = new WeakHashMap<Constructor, Class[]>(
0295: 10);
0296:
0297: private static Class[] getConstructors(Constructor cns) {
0298: Class[] parms = CONSTRUCTOR_PARMS_CACHE.get(cns);
0299: if (parms != null)
0300: return parms;
0301: else {
0302: parms = cns.getParameterTypes();
0303: CONSTRUCTOR_PARMS_CACHE.put(cns, parms);
0304: return parms;
0305: }
0306: }
0307:
0308: public static Constructor getBestConstructorCanadidate(
0309: Object[] arguments, Class cls) {
0310: Class[] parmTypes;
0311: Constructor bestCandidate = null;
0312: int bestScore = 0;
0313: int score = 0;
0314:
0315: Class[] targetParms = new Class[arguments.length];
0316:
0317: for (int i = 0; i < arguments.length; i++) {
0318: if (arguments[i] != null) {
0319: targetParms[i] = arguments[i].getClass();
0320: }
0321: }
0322: Integer hash = createClassSignatureHash(cls, targetParms);
0323:
0324: Map<Integer, Constructor> cache = RESOLVED_CONST_CACHE.get(cls);
0325: if (cache != null) {
0326: if ((bestCandidate = cache.get(hash)) != null)
0327: return bestCandidate;
0328: }
0329:
0330: for (Constructor construct : getConstructors(cls)) {
0331: if ((parmTypes = getConstructors(construct)).length != arguments.length)
0332: continue;
0333: else if (arguments.length == 0 && parmTypes.length == 0)
0334: return construct;
0335:
0336: for (int i = 0; i < arguments.length; i++) {
0337: if (targetParms[i] == null) {
0338: if (!parmTypes[i].isPrimitive())
0339: score += 5;
0340: else {
0341: score = 0;
0342: break;
0343: }
0344: } else if (parmTypes[i] == targetParms[i]) {
0345: score += 5;
0346: } else if (parmTypes[i].isPrimitive()
0347: && boxPrimitive(parmTypes[i]) == targetParms[i]) {
0348: score += 4;
0349: } else if (targetParms[i].isPrimitive()
0350: && unboxPrimitive(targetParms[i]) == parmTypes[i]) {
0351: score += 4;
0352: } else if (isNumericallyCoercible(targetParms[i],
0353: parmTypes[i])) {
0354: score += 3;
0355: } else if (parmTypes[i]
0356: .isAssignableFrom(targetParms[i])) {
0357: score += 2;
0358: } else if (canConvert(parmTypes[i], targetParms[i])) {
0359: score += 1;
0360: } else {
0361: score = 0;
0362: break;
0363: }
0364: }
0365:
0366: if (score != 0 && score > bestScore) {
0367: bestCandidate = construct;
0368: bestScore = score;
0369: }
0370: score = 0;
0371:
0372: }
0373:
0374: if (bestCandidate != null) {
0375: if (cache == null) {
0376: RESOLVED_CONST_CACHE
0377: .put(
0378: cls,
0379: cache = new WeakHashMap<Integer, Constructor>());
0380: }
0381: cache.put(hash, bestCandidate);
0382: }
0383:
0384: return bestCandidate;
0385: }
0386:
0387: private static Map<ClassLoader, Map<String, Class>> CLASS_RESOLVER_CACHE = new WeakHashMap<ClassLoader, Map<String, Class>>(
0388: 1, 1.0f);
0389: private static Map<Class, Constructor[]> CLASS_CONSTRUCTOR_CACHE = new WeakHashMap<Class, Constructor[]>(
0390: 10);
0391:
0392: public static Class createClassSafe(String className) {
0393: try {
0394: return createClass(className);
0395: } catch (ClassNotFoundException e) {
0396: return null;
0397: }
0398: }
0399:
0400: public static Class createClass(String className)
0401: throws ClassNotFoundException {
0402: ClassLoader classLoader = currentThread()
0403: .getContextClassLoader();
0404: Map<String, Class> cache = CLASS_RESOLVER_CACHE
0405: .get(classLoader);
0406: if (cache == null) {
0407: CLASS_RESOLVER_CACHE.put(classLoader,
0408: cache = new WeakHashMap<String, Class>(10));
0409: }
0410:
0411: Class cls;
0412:
0413: if ((cls = cache.get(className)) != null) {
0414: return cls;
0415: } else {
0416: try {
0417: cls = currentThread().getContextClassLoader()
0418: .loadClass(className);
0419: } catch (ClassNotFoundException e) {
0420: /**
0421: * Now try the system classloader.
0422: */
0423: cls = Class.forName(className);
0424: }
0425:
0426: cache.put(className, cls);
0427: return cls;
0428: }
0429: }
0430:
0431: public static Constructor[] getConstructors(Class cls) {
0432: Constructor[] cns = CLASS_CONSTRUCTOR_CACHE.get(cls);
0433: if (cns != null) {
0434: return cns;
0435: } else {
0436: CLASS_CONSTRUCTOR_CACHE.put(cls, cns = cls
0437: .getConstructors());
0438: return cns;
0439: }
0440: }
0441:
0442: public static String[] captureContructorAndResidual(String token) {
0443: char[] cs = token.toCharArray();
0444:
0445: int depth = 0;
0446:
0447: for (int i = 0; i < cs.length; i++) {
0448: switch (cs[i]) {
0449: case '(':
0450: depth++;
0451: continue;
0452: case ')':
0453: if (1 == depth--) {
0454: return new String[] { new String(cs, 0, ++i),
0455: new String(cs, i, cs.length - i) };
0456: }
0457: }
0458: }
0459: return new String[] { token };
0460: }
0461:
0462: public static String[] captureContructorAndResidual(char[] cs) {
0463: int depth = 0;
0464: for (int i = 0; i < cs.length; i++) {
0465: switch (cs[i]) {
0466: case '(':
0467: depth++;
0468: continue;
0469: case ')':
0470: if (1 == depth--) {
0471: return new String[] { new String(cs, 0, ++i),
0472: new String(cs, i, cs.length - i).trim() };
0473: }
0474: }
0475: }
0476: return new String[] { new String(cs) };
0477: }
0478:
0479: public static Class boxPrimitive(Class cls) {
0480: if (cls == int.class || cls == Integer.class) {
0481: return Integer.class;
0482: } else if (cls == int[].class || cls == Integer[].class) {
0483: return Integer[].class;
0484: } else if (cls == long.class || cls == Long.class) {
0485: return Long.class;
0486: } else if (cls == long[].class || cls == Long[].class) {
0487: return Long[].class;
0488: } else if (cls == short.class || cls == Short.class) {
0489: return Short.class;
0490: } else if (cls == short[].class || cls == Short[].class) {
0491: return Short[].class;
0492: } else if (cls == double.class || cls == Double.class) {
0493: return Double.class;
0494: } else if (cls == double[].class || cls == Double[].class) {
0495: return Double[].class;
0496: } else if (cls == float.class || cls == Float.class) {
0497: return Float.class;
0498: } else if (cls == float[].class || cls == Float[].class) {
0499: return Float[].class;
0500: } else if (cls == boolean.class || cls == Boolean.class) {
0501: return Boolean.class;
0502: } else if (cls == boolean[].class || cls == Boolean[].class) {
0503: return Boolean[].class;
0504: } else if (cls == byte.class || cls == Byte.class) {
0505: return Byte.class;
0506: } else if (cls == byte[].class || cls == Byte[].class) {
0507: return Byte[].class;
0508: }
0509:
0510: return null;
0511: }
0512:
0513: public static Class unboxPrimitive(Class cls) {
0514: if (cls == Integer.class || cls == int.class) {
0515: return int.class;
0516: } else if (cls == Integer[].class || cls == int[].class) {
0517: return int[].class;
0518: } else if (cls == Long.class || cls == long.class) {
0519: return long.class;
0520: } else if (cls == Long[].class || cls == long[].class) {
0521: return long[].class;
0522: } else if (cls == Short.class || cls == short.class) {
0523: return short.class;
0524: } else if (cls == Short[].class || cls == short[].class) {
0525: return short[].class;
0526: } else if (cls == Double.class || cls == double.class) {
0527: return double.class;
0528: } else if (cls == Double[].class || cls == double[].class) {
0529: return double[].class;
0530: } else if (cls == Float.class || cls == float.class) {
0531: return float.class;
0532: } else if (cls == Float[].class || cls == float[].class) {
0533: return float[].class;
0534: } else if (cls == Boolean.class || cls == boolean.class) {
0535: return boolean.class;
0536: } else if (cls == Boolean[].class || cls == boolean[].class) {
0537: return boolean[].class;
0538: } else if (cls == Byte.class || cls == byte.class) {
0539: return byte.class;
0540: } else if (cls == Byte[].class || cls == byte[].class) {
0541: return byte[].class;
0542: }
0543:
0544: return null;
0545: }
0546:
0547: public static boolean containsCheck(Object compareTo,
0548: Object compareTest) {
0549: if (compareTo == null)
0550: return false;
0551: else if (compareTo instanceof String)
0552: // @todo use String.contains once we move to jdk1.5
0553: return ((String) compareTo).indexOf(valueOf(compareTest)) > -1;
0554: else if (compareTo instanceof Collection)
0555: return ((Collection) compareTo).contains(compareTest);
0556: else if (compareTo instanceof Map)
0557: return ((Map) compareTo).containsKey(compareTest);
0558: else if (compareTo.getClass().isArray()) {
0559: for (Object o : ((Object[]) compareTo)) {
0560: if (compareTest == null && o == null)
0561: return true;
0562: else if ((Boolean) doOperations(o, Operator.EQUAL,
0563: compareTest))
0564: return true;
0565: }
0566: }
0567: return false;
0568: }
0569:
0570: public static int createClassSignatureHash(Class declaring,
0571: Class[] sig) {
0572: int hash = 0;
0573: for (Class cls : sig) {
0574: if (cls != null)
0575: hash += cls.hashCode();
0576: }
0577:
0578: return hash + sig.length + declaring.hashCode();
0579: }
0580:
0581: public static char handleEscapeSequence(char escapedChar) {
0582: switch (escapedChar) {
0583: case '\\':
0584: return '\\';
0585: case 't':
0586: return '\t';
0587: case 'r':
0588: return '\r';
0589: case 'n':
0590: return '\n';
0591: case '\'':
0592: return '\'';
0593: case '"':
0594: return '"';
0595: default:
0596: throw new ParseException("illegal escape sequence: "
0597: + escapedChar);
0598: }
0599: }
0600:
0601: public static char[] createShortFormOperativeAssignment(
0602: String name, char[] statement, int operation) {
0603: if (operation == -1) {
0604: return statement;
0605: }
0606:
0607: char[] stmt;
0608: char op = 0;
0609: switch (operation) {
0610: case Operator.ADD:
0611: op = '+';
0612: break;
0613: case Operator.SUB:
0614: op = '-';
0615: break;
0616: case Operator.MULT:
0617: op = '*';
0618: break;
0619: case Operator.DIV:
0620: op = '/';
0621: break;
0622: case Operator.BW_AND:
0623: op = '&';
0624: break;
0625: case Operator.BW_OR:
0626: op = '|';
0627: break;
0628: }
0629:
0630: arraycopy(name.toCharArray(), 0, (stmt = new char[name.length()
0631: + statement.length + 1]), 0, name.length());
0632: stmt[name.length()] = op;
0633: arraycopy(statement, 0, stmt, name.length() + 1,
0634: statement.length);
0635:
0636: return stmt;
0637: }
0638:
0639: public static TypeInjectionResolverFactoryImpl findTypeInjectionResolverFactory(
0640: VariableResolverFactory factory) {
0641: VariableResolverFactory v = factory;
0642: while (v != null) {
0643: if (v instanceof TypeInjectionResolverFactoryImpl) {
0644: return (TypeInjectionResolverFactoryImpl) v;
0645: }
0646: v = v.getNextFactory();
0647: }
0648:
0649: if (factory == null) {
0650: throw new OptimizationFailure(
0651: "unable to import classes. no variable resolver factory available.");
0652: } else {
0653: return ResolverTools.appendFactory(factory,
0654: new TypeInjectionResolverFactoryImpl());
0655: }
0656: }
0657:
0658: public static ClassImportResolverFactory findClassImportResolverFactory(
0659: VariableResolverFactory factory) {
0660: VariableResolverFactory v = factory;
0661: while (v != null) {
0662: if (v instanceof ClassImportResolverFactory) {
0663: return (ClassImportResolverFactory) v;
0664: }
0665: v = v.getNextFactory();
0666: }
0667:
0668: if (factory == null) {
0669: throw new OptimizationFailure(
0670: "unable to import classes. no variable resolver factory available.");
0671: } else {
0672: return ResolverTools.insertFactory(factory,
0673: new ClassImportResolverFactory());
0674: }
0675: }
0676:
0677: public static StaticMethodImportResolverFactory findStaticMethodImportResolverFactory(
0678: VariableResolverFactory factory) {
0679: VariableResolverFactory v = factory;
0680: while (v != null) {
0681: if (v instanceof StaticMethodImportResolverFactory) {
0682: return (StaticMethodImportResolverFactory) v;
0683: }
0684: v = v.getNextFactory();
0685: }
0686:
0687: if (factory == null) {
0688: throw new OptimizationFailure(
0689: "unable to import classes. no variable resolver factory available.");
0690: } else {
0691: return ResolverTools.insertFactory(factory,
0692: new StaticMethodImportResolverFactory());
0693: }
0694: }
0695:
0696: public static Class findClass(VariableResolverFactory factory,
0697: String name) throws ClassNotFoundException {
0698: try {
0699: if (AbstractParser.LITERALS.containsKey(name)) {
0700: return (Class) AbstractParser.LITERALS.get(name);
0701: } else if (factory != null && factory.isResolveable(name)) {
0702: return (Class) factory.getVariableResolver(name)
0703: .getValue();
0704: } else if (getCurrentThreadParserContext() != null
0705: && getCurrentThreadParserContext().hasImport(name)) {
0706: return getCurrentThreadParserContext().getImport(name);
0707: } else {
0708: return createClass(name);
0709: }
0710: } catch (ClassNotFoundException e) {
0711: throw e;
0712: } catch (Exception e) {
0713: throw new CompileException("class not found: " + name, e);
0714: }
0715: }
0716:
0717: public static boolean debug(String str) {
0718: return true;
0719: }
0720:
0721: public static boolean debug(Throwable t) {
0722: t.printStackTrace();
0723: return true;
0724: }
0725:
0726: public static char[] subset(char[] array, int start, int length) {
0727: char[] newArray = new char[length];
0728:
0729: for (int i = 0; i < newArray.length; i++) {
0730: newArray[i] = array[i + start];
0731: }
0732:
0733: return newArray;
0734: }
0735:
0736: public static char[] subset(char[] array, int start) {
0737: char[] newArray = new char[array.length - start];
0738: // arraycopy(array, start, newArray, 0, newArray.length);
0739:
0740: for (int i = 0; i < newArray.length; i++) {
0741: newArray[i] = array[i + start];
0742: }
0743:
0744: return newArray;
0745: }
0746:
0747: private static Map<Class, Integer> typeResolveMap = new HashMap<Class, Integer>();
0748:
0749: static {
0750: Map<Class, Integer> t = typeResolveMap;
0751: t.put(BigDecimal.class, DataTypes.BIG_DECIMAL);
0752: t.put(BigInteger.class, DataTypes.BIG_INTEGER);
0753: t.put(String.class, DataTypes.STRING);
0754:
0755: t.put(int.class, DataTypes.INTEGER);
0756: t.put(Integer.class, DataTypes.W_INTEGER);
0757:
0758: t.put(short.class, DataTypes.SHORT);
0759: t.put(Short.class, DataTypes.W_SHORT);
0760:
0761: t.put(float.class, DataTypes.FLOAT);
0762: t.put(Float.class, DataTypes.W_FLOAT);
0763:
0764: t.put(double.class, DataTypes.DOUBLE);
0765: t.put(Double.class, DataTypes.W_DOUBLE);
0766:
0767: t.put(long.class, DataTypes.LONG);
0768: t.put(Long.class, DataTypes.W_LONG);
0769:
0770: t.put(boolean.class, DataTypes.BOOLEAN);
0771: t.put(Boolean.class, DataTypes.W_BOOLEAN);
0772:
0773: t.put(byte.class, DataTypes.BYTE);
0774: t.put(Byte.class, DataTypes.W_BYTE);
0775:
0776: t.put(char.class, DataTypes.CHAR);
0777: t.put(Character.class, DataTypes.W_CHAR);
0778:
0779: t.put(BlankLiteral.class, DataTypes.EMPTY);
0780:
0781: }
0782:
0783: public static int resolveType(Class cls) {
0784: Integer i = typeResolveMap.get(cls);
0785: if (i == null)
0786: return DataTypes.OBJECT;
0787: else {
0788: return i;
0789: }
0790: }
0791:
0792: public static int __resolveType(Class cls) {
0793: if (cls == null)
0794: return 0;
0795: if (BigDecimal.class == cls)
0796: return DataTypes.BIG_DECIMAL;
0797:
0798: if (BigInteger.class == cls)
0799: return DataTypes.BIG_INTEGER;
0800:
0801: if (String.class == cls)
0802: return DataTypes.STRING;
0803:
0804: if (int.class == cls)
0805: return DataTypes.INTEGER;
0806: if (short.class == cls)
0807: return DataTypes.SHORT;
0808: if (float.class == cls)
0809: return DataTypes.FLOAT;
0810: if (double.class == cls)
0811: return DataTypes.DOUBLE;
0812: if (long.class == cls)
0813: return DataTypes.LONG;
0814: if (boolean.class == cls)
0815: return DataTypes.BOOLEAN;
0816: if (byte.class == cls)
0817: return DataTypes.BYTE;
0818: if (char.class == cls)
0819: return DataTypes.CHAR;
0820:
0821: if (Integer.class == cls)
0822: return DataTypes.W_INTEGER;
0823: if (Short.class == cls)
0824: return DataTypes.W_SHORT;
0825: if (Float.class == cls)
0826: return DataTypes.W_FLOAT;
0827: if (Double.class == cls)
0828: return DataTypes.W_DOUBLE;
0829: if (Long.class == cls)
0830: return DataTypes.W_LONG;
0831: if (Boolean.class == cls)
0832: return DataTypes.W_BOOLEAN;
0833: if (Byte.class == cls)
0834: return DataTypes.W_BYTE;
0835: if (Character.class == cls)
0836: return DataTypes.W_CHAR;
0837:
0838: if (BlankLiteral.class == cls)
0839: return DataTypes.EMPTY;
0840:
0841: if (Unit.class.isAssignableFrom(cls))
0842: return DataTypes.UNIT;
0843:
0844: return DataTypes.OBJECT;
0845: }
0846:
0847: public static Object valueOnly(Object o) {
0848: return (o instanceof ASTNode) ? ((ASTNode) o).getLiteralValue()
0849: : o;
0850: }
0851:
0852: public static boolean isNumericallyCoercible(Class target,
0853: Class parm) {
0854: Class boxedTarget = target.isPrimitive() ? boxPrimitive(target)
0855: : target;
0856:
0857: if (boxedTarget != null
0858: && Number.class.isAssignableFrom(target)) {
0859: Class boxedParm = parm.isPrimitive() ? boxPrimitive(parm)
0860: : parm;
0861:
0862: if (boxedParm != null) {
0863: return Number.class.isAssignableFrom(boxedParm);
0864: }
0865: }
0866: return false;
0867: }
0868:
0869: public static Object handleParserEgress(Object result,
0870: boolean returnBigDecimal) {
0871:
0872: if (result instanceof BigDecimal) {
0873: int scale = ((BigDecimal) result).scale();
0874: if (returnBigDecimal)
0875: return result;
0876: else if (scale > 14) {
0877: return ((BigDecimal) result).doubleValue();
0878: } else if (scale > 0) {
0879: return ((BigDecimal) result).floatValue();
0880: } else if (((BigDecimal) result).longValue() > Integer.MAX_VALUE) {
0881: return ((BigDecimal) result).longValue();
0882: } else {
0883: return ((BigDecimal) result).intValue();
0884: }
0885: } else
0886: return result;
0887:
0888: }
0889:
0890: public static Method determineActualTargetMethod(Method method) {
0891: String name = method.getName();
0892:
0893: /**
0894: * Follow our way up the class heirarchy until we find the physical target method.
0895: */
0896: for (Class cls : method.getDeclaringClass().getInterfaces()) {
0897: for (Method meth : cls.getMethods()) {
0898: if (meth.getParameterTypes().length == 0
0899: && name.equals(meth.getName())) {
0900: return meth;
0901: }
0902: }
0903: }
0904:
0905: return null;
0906: }
0907:
0908: public static Object doOperations(Object val1, int operation,
0909: Object val2) {
0910: return MATH_PROCESSOR.doOperation(val1, operation, val2);
0911: }
0912:
0913: public static Object increment(Object o) {
0914: if (o instanceof Integer) {
0915: return (Integer) o + 1;
0916: } else if (o instanceof Double) {
0917: return (Double) o + 1;
0918: } else if (o instanceof Float) {
0919: return (Float) o + 1;
0920: } else if (o instanceof Short) {
0921: return (Short) o + 1;
0922: } else if (o instanceof Character) {
0923: return (Character) o + 1;
0924: } else {
0925: throw new CompileException("unable to increment type: "
0926: + (o != null ? o.getClass().getName() : "null"));
0927: }
0928: }
0929:
0930: public static Map<String, String> parseParameters(char[] parms) {
0931: Map<String, String> allParms = new HashMap<String, String>();
0932:
0933: boolean capture = false;
0934: int start = 0;
0935:
0936: String parmName = null;
0937: int i = 0;
0938: for (; i < parms.length; i++) {
0939: switch (parms[i]) {
0940: case '=':
0941: // i++;
0942: parmName = new String(parms, start, ++i - start - 1)
0943: .trim();
0944: capture = true;
0945: start = i;
0946: break;
0947:
0948: case ',':
0949: if (capture) {
0950: allParms.put(parmName, new String(parms, start, i
0951: - start).trim());
0952: start = ++i;
0953: capture = false;
0954: break;
0955: }
0956: }
0957: }
0958:
0959: if (capture) {
0960: allParms.put(parmName, new String(parms, start, i - start)
0961: .trim());
0962: }
0963:
0964: return allParms;
0965: }
0966:
0967: /**
0968: * This is an important aspect of the core parser tools. This method is used throughout the core parser
0969: * and sub-lexical parsers to capture a balanced capture between opening and terminating tokens such as:
0970: * <em>( [ { ' " </em>
0971: * <br>
0972: * <br>
0973: * For example: ((foo + bar + (bar - foo)) * 20;<br>
0974: * <br>
0975: * <p/>
0976: * If a balanced capture is performed from position 2, we get "(foo + bar + (bar - foo))" back.<br>
0977: * If a balanced capture is performed from position 15, we get "(bar - foo)" back.<br>
0978: * Etc.
0979: *
0980: * @param chars -
0981: * @param start -
0982: * @param type -
0983: * @return -
0984: */
0985: public static int balancedCapture(char[] chars, int start, char type) {
0986: int depth = 1;
0987: char term = type;
0988: switch (type) {
0989: case '[':
0990: term = ']';
0991: break;
0992: case '{':
0993: term = '}';
0994: break;
0995: case '(':
0996: term = ')';
0997: break;
0998: }
0999:
1000: if (type == term) {
1001: for (start++; start < chars.length; start++) {
1002: if (chars[start] == type) {
1003: return start;
1004: }
1005: }
1006: } else {
1007: for (start++; start < chars.length; start++) {
1008: if (chars[start] == '\'' || chars[start] == '"') {
1009: start = captureStringLiteral(chars[start], chars,
1010: start, chars.length);
1011: } else if (chars[start] == type) {
1012: depth++;
1013: } else if (chars[start] == term && --depth == 0) {
1014: return start;
1015: }
1016: }
1017: }
1018:
1019: switch (type) {
1020: case '[':
1021: throw new CompileException("unbalanced braces [ ... ]",
1022: chars, start);
1023: case '{':
1024: throw new CompileException("unbalanced braces { ... }",
1025: chars, start);
1026: case '(':
1027: throw new CompileException("unbalanced braces ( ... )",
1028: chars, start);
1029: default:
1030: throw new CompileException("unterminated string literal",
1031: chars, start);
1032:
1033: }
1034: }
1035:
1036: public static int[] balancedCaptureWithLineAccounting(char[] chars,
1037: int start, char type) {
1038: int depth = 1;
1039: char term = type;
1040: switch (type) {
1041: case '[':
1042: term = ']';
1043: break;
1044: case '{':
1045: term = '}';
1046: break;
1047: case '(':
1048: term = ')';
1049: break;
1050: }
1051:
1052: if (type == term) {
1053: for (start++; start < chars.length; start++) {
1054: if (chars[start] == type) {
1055: return new int[] { start, 0 };
1056: }
1057: }
1058: } else {
1059: int lines = 0;
1060:
1061: for (start++; start < chars.length; start++) {
1062: if (isWhitespace(chars[start])) {
1063: switch (chars[start]) {
1064: case '\r':
1065: continue;
1066: case '\n':
1067: lines++;
1068: }
1069: }
1070:
1071: else if (chars[start] == '\'' || chars[start] == '"') {
1072: start = captureStringLiteral(chars[start], chars,
1073: start, chars.length);
1074: } else if (chars[start] == type) {
1075: depth++;
1076: } else if (chars[start] == term && --depth == 0) {
1077: return new int[] { start, lines };
1078: }
1079:
1080: }
1081: }
1082:
1083: // return new int[]{-1, 0};
1084:
1085: switch (type) {
1086: case '[':
1087: throw new CompileException("unbalanced braces [ ... ]",
1088: chars, start);
1089: case '{':
1090: throw new CompileException("unbalanced braces { ... }",
1091: chars, start);
1092: case '(':
1093: throw new CompileException("unbalanced braces ( ... )",
1094: chars, start);
1095: default:
1096: throw new CompileException("unterminated string literal",
1097: chars, start);
1098:
1099: }
1100: }
1101:
1102: public static String handleStringEscapes(char[] input) {
1103: int escapes = 0;
1104: for (int i = 0; i < input.length; i++) {
1105: if (input[i] == '\\') {
1106: input[i++] = 0;
1107: input[i] = handleEscapeSequence(input[i]);
1108: escapes++;
1109: }
1110: }
1111:
1112: char[] processedEscapeString = new char[input.length - escapes];
1113: int cursor = 0;
1114: for (char aName : input) {
1115: if (aName == 0) {
1116: continue;
1117: }
1118: processedEscapeString[cursor++] = aName;
1119: }
1120:
1121: return new String(processedEscapeString);
1122: }
1123:
1124: public static int captureStringLiteral(final char type,
1125: final char[] expr, int cursor, int length) {
1126: while (++cursor < length && expr[cursor] != type) {
1127: if (expr[cursor] == '\\')
1128: handleEscapeSequence(expr[++cursor]);
1129: }
1130:
1131: if (cursor == length || expr[cursor] != type) {
1132: throw new CompileException("unterminated literal", expr,
1133: cursor);
1134: }
1135:
1136: return cursor;
1137: }
1138:
1139: /**
1140: * REMOVE THIS WITH JDK1.4 COMPATIBILITY! COMPENSATES FOR LACK OF getSimpleName IN java.lang.Class -- DIE 1.4!
1141: *
1142: * @param cls -- class reference
1143: * @return Simple name of class
1144: */
1145: public static String getSimpleClassName(Class cls) {
1146: if (JDK_14_COMPATIBILITY) {
1147: int lastIndex = cls.getName().lastIndexOf('$');
1148: if (lastIndex < 0) {
1149: lastIndex = cls.getName().lastIndexOf('.');
1150: }
1151: if (cls.isArray()) {
1152: return cls.getName().substring(lastIndex + 1) + "[]";
1153: } else {
1154: return cls.getName().substring(lastIndex + 1);
1155: }
1156: } else {
1157: return cls.getSimpleName();
1158: }
1159: }
1160:
1161: public static void checkNameSafety(String name) {
1162: if (isReservedWord(name)) {
1163: throw new CompileException("illegal use of reserved word: "
1164: + name);
1165: }
1166: }
1167:
1168: public static FileWriter getDebugFileWriter() throws IOException {
1169: return new FileWriter(new File(MVEL
1170: .getDebuggingOutputFileName()), true);
1171: }
1172:
1173: public static boolean isPrimitiveWrapper(Class clazz) {
1174: return clazz == Integer.class || clazz == Boolean.class
1175: || clazz == Long.class || clazz == Double.class
1176: || clazz == Float.class || clazz == Short.class
1177: || clazz == Byte.class || clazz == Character.class;
1178: }
1179:
1180: public static Serializable subCompileExpression(String expression) {
1181: return optimizeTree(new ExpressionCompiler(expression)
1182: ._compile());
1183: }
1184:
1185: public static Serializable subCompileExpression(char[] expression) {
1186: return optimizeTree(new ExpressionCompiler(expression)
1187: ._compile());
1188: }
1189:
1190: public static Serializable subCompileExpression(char[] expression,
1191: ParserContext ctx) {
1192: return optimizeTree(new ExpressionCompiler(expression, ctx)
1193: ._compile());
1194: }
1195:
1196: public static Serializable subCompileExpression(String expression,
1197: ParserContext ctx) {
1198: return optimizeTree(new ExpressionCompiler(expression, ctx)
1199: ._compile());
1200: }
1201:
1202: public static Serializable optimizeTree(
1203: final CompiledExpression compiled) {
1204: ASTIterator nodes = compiled.getInstructions();
1205:
1206: /**
1207: * If there is only one token, and it's an identifier, we can optimize this as an accessor expression.
1208: */
1209: if (MVEL.isOptimizationEnabled() && nodes.size() == 1) {
1210: ASTNode tk = nodes.firstNode();
1211:
1212: if (tk.isLiteral() && !tk.isThisVal()) {
1213: if ((tk.getFields() & ASTNode.INTEGER32) != 0) {
1214: return new ExecutableLiteral(tk.getIntRegister());
1215: } else {
1216: return new ExecutableLiteral(tk.getLiteralValue());
1217: }
1218: }
1219: return tk.canSerializeAccessor() ? new ExecutableAccessorSafe(
1220: tk, false, compiled.getKnownEgressType())
1221: : new ExecutableAccessor(tk, false, compiled
1222: .getKnownEgressType());
1223:
1224: }
1225:
1226: return compiled;
1227: }
1228:
1229: public static String repeatChar(char c, int times) {
1230: char[] n = new char[times];
1231: for (int i = 0; i < times; i++) {
1232: n[i] = c;
1233: }
1234: return new String(n);
1235: }
1236:
1237: public static char[] loadFromFile(File file) throws IOException {
1238: if (!file.exists())
1239: throw new CompileException("cannot find file: "
1240: + file.getName());
1241:
1242: FileInputStream inStream = null;
1243: ReadableByteChannel fc = null;
1244: try {
1245: fc = (inStream = new FileInputStream(file)).getChannel();
1246: ByteBuffer buf = allocateDirect(10);
1247:
1248: StringAppender sb = new StringAppender((int) file.length());
1249:
1250: int read = 0;
1251: while (read >= 0) {
1252: buf.rewind();
1253: read = fc.read(buf);
1254: buf.rewind();
1255:
1256: for (; read > 0; read--) {
1257: sb.append((char) buf.get());
1258: }
1259: }
1260:
1261: //noinspection unchecked
1262: return sb.toChars();
1263: } catch (FileNotFoundException e) {
1264: // this can't be thrown, we check for this explicitly.
1265: } finally {
1266: if (inStream != null)
1267: inStream.close();
1268: if (fc != null)
1269: fc.close();
1270: }
1271:
1272: return null;
1273: }
1274:
1275: private static Unsafe _getUnsafe() {
1276: try {
1277: Field field = Unsafe.class.getDeclaredField("theUnsafe");
1278: field.setAccessible(true);
1279: return (Unsafe) field.get(null);
1280: } catch (Exception ex) {
1281: throw new RuntimeException("can't get Unsafe instance", ex);
1282: }
1283: }
1284:
1285: private static final Unsafe unsafe__ = _getUnsafe();
1286:
1287: public static Unsafe getUnsafe() {
1288: return unsafe__;
1289: }
1290:
1291: }
|