PageRenderTime 78ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main/java/org/mvel2/util/ParseTools.java

https://github.com/sherl0cks/mvel
Java | 2197 lines | 1988 code | 141 blank | 68 comment | 505 complexity | 92070d1fdd34129b6a9e291c43e0c04a MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /**
  2. * MVEL 2.0
  3. * Copyright (C) 2007 The Codehaus
  4. * Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.mvel2.util;
  19. import org.mvel2.*;
  20. import org.mvel2.ast.ASTNode;
  21. import org.mvel2.compiler.*;
  22. import org.mvel2.integration.VariableResolverFactory;
  23. import org.mvel2.integration.impl.ClassImportResolverFactory;
  24. import org.mvel2.math.MathProcessor;
  25. import java.io.*;
  26. import java.lang.ref.WeakReference;
  27. import java.lang.reflect.Constructor;
  28. import java.lang.reflect.Method;
  29. import java.lang.reflect.Modifier;
  30. import java.math.BigDecimal;
  31. import java.math.BigInteger;
  32. import java.math.MathContext;
  33. import java.nio.ByteBuffer;
  34. import java.nio.channels.ReadableByteChannel;
  35. import java.util.*;
  36. import static java.lang.Class.forName;
  37. import static java.lang.Double.parseDouble;
  38. import static java.lang.String.valueOf;
  39. import static java.lang.System.arraycopy;
  40. import static java.lang.Thread.currentThread;
  41. import static java.nio.ByteBuffer.allocateDirect;
  42. import static org.mvel2.DataConversion.canConvert;
  43. import static org.mvel2.DataTypes.*;
  44. import static org.mvel2.MVEL.getDebuggingOutputFileName;
  45. import static org.mvel2.compiler.AbstractParser.LITERALS;
  46. import static org.mvel2.integration.ResolverTools.appendFactory;
  47. import static org.mvel2.integration.ResolverTools.insertFactory;
  48. @SuppressWarnings({"ManualArrayCopy"})
  49. public class ParseTools {
  50. public static final String[] EMPTY_STR_ARR = new String[0];
  51. public static final Object[] EMPTY_OBJ_ARR = new Object[0];
  52. public static final Class[] EMPTY_CLS_ARR = new Class[0];
  53. static {
  54. try {
  55. double version = parseDouble(System.getProperty("java.version").substring(0, 3));
  56. if (version < 1.5) {
  57. throw new RuntimeException("unsupported java version: " + version);
  58. }
  59. }
  60. catch (RuntimeException e) {
  61. throw e;
  62. }
  63. catch (Exception e) {
  64. throw new RuntimeException("unable to initialize math processor", e);
  65. }
  66. }
  67. public static List<char[]> parseMethodOrConstructor(char[] parm) {
  68. int start = -1;
  69. for (int i = 0; i < parm.length; i++) {
  70. if (parm[i] == '(') {
  71. start = ++i;
  72. break;
  73. }
  74. }
  75. if (start != -1) {
  76. return parseParameterList(parm, --start + 1, balancedCapture(parm, start, '(') - start - 1);
  77. }
  78. return Collections.emptyList();
  79. }
  80. public static String[] parseParameterDefList(char[] parm, int offset, int length) {
  81. List<String> list = new LinkedList<String>();
  82. if (length == -1)
  83. length = parm.length;
  84. int start = offset;
  85. int i = offset;
  86. int end = i + length;
  87. String s;
  88. for (; i < end; i++) {
  89. switch (parm[i]) {
  90. case '(':
  91. case '[':
  92. case '{':
  93. i = balancedCapture(parm, i, parm[i]);
  94. continue;
  95. case '\'':
  96. i = captureStringLiteral('\'', parm, i, parm.length);
  97. continue;
  98. case '"':
  99. i = captureStringLiteral('"', parm, i, parm.length);
  100. continue;
  101. case ',':
  102. if (i > start) {
  103. while (isWhitespace(parm[start]))
  104. start++;
  105. checkNameSafety(s = new String(parm, start, i - start));
  106. list.add(s);
  107. }
  108. while (isWhitespace(parm[i]))
  109. i++;
  110. start = i + 1;
  111. continue;
  112. default:
  113. if (!isWhitespace(parm[i]) && !isIdentifierPart(parm[i])) {
  114. throw new CompileException("expected parameter", parm, start);
  115. }
  116. }
  117. }
  118. if (start < (length + offset) && i > start) {
  119. if ((s = createStringTrimmed(parm, start, i - start)).length() > 0) {
  120. checkNameSafety(s);
  121. list.add(s);
  122. }
  123. }
  124. else if (list.size() == 0) {
  125. if ((s = createStringTrimmed(parm, start, length)).length() > 0) {
  126. checkNameSafety(s);
  127. list.add(s);
  128. }
  129. }
  130. return list.toArray(new String[list.size()]);
  131. }
  132. public static List<char[]> parseParameterList(char[] parm, int offset, int length) {
  133. List<char[]> list = new ArrayList<char[]>();
  134. if (length == -1)
  135. length = parm.length;
  136. int start = offset;
  137. int i = offset;
  138. int end = i + length;
  139. for (; i < end; i++) {
  140. switch (parm[i]) {
  141. case '(':
  142. case '[':
  143. case '{':
  144. i = balancedCapture(parm, i, parm[i]);
  145. continue;
  146. case '\'':
  147. i = captureStringLiteral('\'', parm, i, parm.length);
  148. continue;
  149. case '"':
  150. i = captureStringLiteral('"', parm, i, parm.length);
  151. continue;
  152. case ',':
  153. if (i > start) {
  154. while (isWhitespace(parm[start]))
  155. start++;
  156. list.add(subsetTrimmed(parm, start, i - start));
  157. }
  158. while (isWhitespace(parm[i]))
  159. i++;
  160. start = i + 1;
  161. }
  162. }
  163. if (start < (length + offset) && i > start) {
  164. char[] s = subsetTrimmed(parm, start, i - start);
  165. if (s.length > 0)
  166. list.add(s);
  167. }
  168. else if (list.size() == 0) {
  169. char[] s = subsetTrimmed(parm, start, length);
  170. if (s.length > 0)
  171. list.add(s);
  172. }
  173. return list;
  174. }
  175. private static Map<String, Map<Integer, WeakReference<Method>>> RESOLVED_METH_CACHE = new WeakHashMap<String, Map<Integer, WeakReference<Method>>>(10);
  176. public static Method getBestCandidate(Object[] arguments, String method, Class decl, Method[] methods, boolean requireExact) {
  177. Class[] targetParms = new Class[arguments.length];
  178. for (int i = 0; i != arguments.length; i++) {
  179. targetParms[i] = arguments[i] != null ? arguments[i].getClass() : null;
  180. }
  181. return getBestCandidate(targetParms, method, decl, methods, requireExact);
  182. }
  183. public static Method getBestCandidate(Class[] arguments, String method, Class decl, Method[] methods, boolean requireExact) {
  184. return getBestCandidate(arguments, method, decl, methods, requireExact, false);
  185. }
  186. public static Method getBestCandidate(Class[] arguments, String method, Class decl, Method[] methods, boolean requireExact, boolean classTarget) {
  187. if (methods.length == 0) {
  188. return null;
  189. }
  190. Class[] parmTypes;
  191. Method bestCandidate = null;
  192. int bestScore = 0;
  193. boolean retry = false;
  194. Integer hash = createClassSignatureHash(decl, arguments);
  195. Map<Integer, WeakReference<Method>> methCache = RESOLVED_METH_CACHE.get(method);
  196. WeakReference<Method> ref;
  197. if (methCache != null && (ref = methCache.get(hash)) != null && (bestCandidate = ref.get()) != null) {
  198. return bestCandidate;
  199. }
  200. do {
  201. for (Method meth : methods) {
  202. if (classTarget && (meth.getModifiers() & Modifier.STATIC) == 0) continue;
  203. if (method.equals(meth.getName())) {
  204. boolean isVarArgs = meth.isVarArgs();
  205. if ((parmTypes = meth.getParameterTypes()).length != arguments.length && !isVarArgs) {
  206. continue;
  207. }
  208. else if (arguments.length == 0 && parmTypes.length == 0) {
  209. if (bestCandidate == null || bestCandidate.getReturnType().isAssignableFrom(meth.getReturnType())) {
  210. bestCandidate = meth;
  211. }
  212. continue;
  213. }
  214. int score = getMethodScore(arguments, requireExact, parmTypes, isVarArgs);
  215. if (score != 0) {
  216. if (score > bestScore) {
  217. bestCandidate = meth;
  218. bestScore = score;
  219. } else if (score == bestScore) {
  220. if (bestCandidate == null || (bestCandidate.getReturnType() != meth.getReturnType() && bestCandidate.getReturnType().isAssignableFrom(meth.getReturnType()))) {
  221. bestCandidate = meth;
  222. }
  223. }
  224. }
  225. }
  226. }
  227. if (bestCandidate != null) {
  228. if (methCache == null) {
  229. RESOLVED_METH_CACHE.put(method, methCache = new WeakHashMap<Integer, WeakReference<Method>>());
  230. }
  231. methCache.put(hash, new WeakReference<Method>(bestCandidate));
  232. break;
  233. }
  234. if (!retry && decl.isInterface()) {
  235. Method[] objMethods = Object.class.getMethods();
  236. Method[] nMethods = new Method[methods.length + objMethods.length];
  237. for (int i = 0; i < methods.length; i++) {
  238. nMethods[i] = methods[i];
  239. }
  240. for (int i = 0; i < objMethods.length; i++) {
  241. nMethods[i + methods.length] = objMethods[i];
  242. }
  243. methods = nMethods;
  244. retry = true;
  245. }
  246. else {
  247. break;
  248. }
  249. }
  250. while (true);
  251. return bestCandidate;
  252. }
  253. private static int getMethodScore(Class[] arguments, boolean requireExact, Class[] parmTypes, boolean varArgs) {
  254. int score = 0;
  255. for (int i = 0; i != arguments.length; i++) {
  256. Class actualParamType;
  257. if (varArgs && i >= parmTypes.length-1)
  258. actualParamType = parmTypes[parmTypes.length-1].getComponentType();
  259. else
  260. actualParamType = parmTypes[i];
  261. if (arguments[i] == null) {
  262. if (!actualParamType.isPrimitive()) {
  263. score += 6;
  264. }
  265. else {
  266. score = 0;
  267. break;
  268. }
  269. }
  270. else if (actualParamType == arguments[i]) {
  271. score += 7;
  272. }
  273. else if (actualParamType.isPrimitive() && boxPrimitive(actualParamType) == arguments[i]) {
  274. score += 6;
  275. }
  276. else if (arguments[i].isPrimitive() && unboxPrimitive(arguments[i]) == actualParamType) {
  277. score += 6;
  278. }
  279. else if (actualParamType.isAssignableFrom(arguments[i])) {
  280. score += 5;
  281. }
  282. else if (isNumericallyCoercible(arguments[i], actualParamType)) {
  283. score += 4;
  284. }
  285. else if (boxPrimitive(actualParamType).isAssignableFrom(boxPrimitive(arguments[i]))
  286. && Object.class != arguments[i]) {
  287. score += 3 + scoreInterface(actualParamType, arguments[i]);
  288. }
  289. else if (!requireExact && canConvert(actualParamType, arguments[i])) {
  290. if (actualParamType.isArray() && arguments[i].isArray()) score += 1;
  291. else if (actualParamType == char.class && arguments[i] == String.class) score += 1;
  292. score += 1;
  293. }
  294. else if (actualParamType == Object.class || arguments[i] == NullType.class) {
  295. score += 1;
  296. }
  297. else {
  298. score = 0;
  299. break;
  300. }
  301. }
  302. return score;
  303. }
  304. public static int scoreInterface(Class parm, Class arg) {
  305. if (parm.isInterface()) {
  306. Class[] iface = arg.getInterfaces();
  307. if (iface != null) {
  308. for (Class c : iface) {
  309. if (c == parm) return 1;
  310. else if (parm.isAssignableFrom(c)) return scoreInterface(parm, arg.getSuperclass());
  311. }
  312. }
  313. }
  314. return 0;
  315. }
  316. public static Method getExactMatch(String name, Class[] args, Class returnType, Class cls) {
  317. for (Method meth : cls.getMethods()) {
  318. if (name.equals(meth.getName()) && returnType == meth.getReturnType()) {
  319. Class[] parameterTypes = meth.getParameterTypes();
  320. if (parameterTypes.length != args.length) continue;
  321. for (int i = 0; i < parameterTypes.length; i++) {
  322. if (parameterTypes[i] != args[i]) return null;
  323. }
  324. return meth;
  325. }
  326. }
  327. return null;
  328. }
  329. public static Method getWidenedTarget(Method method) {
  330. return getWidenedTarget(method.getDeclaringClass(), method);
  331. }
  332. public static Method getWidenedTarget(Class cls, Method method) {
  333. Method m = method, best = method;
  334. Class[] args = method.getParameterTypes();
  335. String name = method.getName();
  336. Class rt = m.getReturnType();
  337. Class currentCls = cls;
  338. while (currentCls != null) {
  339. for (Class iface : currentCls.getInterfaces()) {
  340. if ((m = getExactMatch(name, args, rt, iface)) != null) {
  341. best = m;
  342. }
  343. }
  344. currentCls = currentCls.getSuperclass();
  345. }
  346. if (best != method) return best;
  347. currentCls = cls;
  348. for (currentCls = cls; currentCls != null; currentCls = currentCls.getSuperclass()) {
  349. if ((m = getExactMatch(name, args, rt, currentCls)) != null) {
  350. best = m;
  351. }
  352. }
  353. return best;
  354. }
  355. private static Map<Class, Map<Integer, WeakReference<Constructor>>> RESOLVED_CONST_CACHE
  356. = new WeakHashMap<Class, Map<Integer, WeakReference<Constructor>>>(10);
  357. private static Map<Constructor, WeakReference<Class[]>> CONSTRUCTOR_PARMS_CACHE
  358. = new WeakHashMap<Constructor, WeakReference<Class[]>>(10);
  359. private static Class[] getConstructors(Constructor cns) {
  360. WeakReference<Class[]> ref = CONSTRUCTOR_PARMS_CACHE.get(cns);
  361. Class[] parms;
  362. if (ref != null && (parms = ref.get()) != null) {
  363. return parms;
  364. }
  365. else {
  366. CONSTRUCTOR_PARMS_CACHE.put(cns, new WeakReference<Class[]>(parms = cns.getParameterTypes()));
  367. return parms;
  368. }
  369. }
  370. public static Constructor getBestConstructorCandidate(Object[] args, Class cls, boolean requireExact) {
  371. Class[] arguments = new Class[args.length];
  372. for (int i = 0; i != args.length; i++) {
  373. if (args[i] != null) {
  374. arguments[i] = args[i].getClass();
  375. }
  376. }
  377. return getBestConstructorCandidate(arguments, cls, requireExact);
  378. }
  379. public static Constructor getBestConstructorCandidate(Class[] arguments, Class cls, boolean requireExact) {
  380. Class[] parmTypes;
  381. Constructor bestCandidate = null;
  382. int bestScore = 0;
  383. Integer hash = createClassSignatureHash(cls, arguments);
  384. Map<Integer, WeakReference<Constructor>> cache = RESOLVED_CONST_CACHE.get(cls);
  385. WeakReference<Constructor> ref;
  386. if (cache != null && (ref = cache.get(hash)) != null && (bestCandidate = ref.get()) != null) {
  387. return bestCandidate;
  388. }
  389. for (Constructor construct : getConstructors(cls)) {
  390. boolean isVarArgs = construct.isVarArgs();
  391. if ((parmTypes = getConstructors(construct)).length != arguments.length && !construct.isVarArgs()) {
  392. continue;
  393. }
  394. else if (arguments.length == 0 && parmTypes.length == 0) {
  395. return construct;
  396. }
  397. int score = getMethodScore(arguments, requireExact, parmTypes, isVarArgs);
  398. if (score != 0 && score > bestScore) {
  399. bestCandidate = construct;
  400. bestScore = score;
  401. }
  402. }
  403. if (bestCandidate != null) {
  404. if (cache == null) {
  405. RESOLVED_CONST_CACHE.put(cls, cache = new WeakHashMap<Integer, WeakReference<Constructor>>());
  406. }
  407. cache.put(hash, new WeakReference<Constructor>(bestCandidate));
  408. }
  409. return bestCandidate;
  410. }
  411. private static Map<ClassLoader, Map<String, WeakReference<Class>>> CLASS_RESOLVER_CACHE
  412. = new WeakHashMap<ClassLoader, Map<String, WeakReference<Class>>>(1, 1.0f);
  413. private static Map<Class, WeakReference<Constructor[]>> CLASS_CONSTRUCTOR_CACHE
  414. = new WeakHashMap<Class, WeakReference<Constructor[]>>(10);
  415. public static Class createClass(String className, ParserContext pCtx) throws ClassNotFoundException {
  416. ClassLoader classLoader = pCtx != null ? pCtx.getClassLoader() : currentThread().getContextClassLoader();
  417. Map<String, WeakReference<Class>> cache = CLASS_RESOLVER_CACHE.get(classLoader);
  418. if (cache == null) {
  419. CLASS_RESOLVER_CACHE.put(classLoader, cache = new WeakHashMap<String, WeakReference<Class>>(10));
  420. }
  421. WeakReference<Class> ref;
  422. Class cls = null;
  423. if ((ref = cache.get(className)) != null && (cls = ref.get()) != null) {
  424. return cls;
  425. }
  426. else {
  427. try {
  428. cls = Class.forName(className, true, classLoader);
  429. }
  430. catch (ClassNotFoundException e) {
  431. /**
  432. * Now try the system classloader.
  433. */
  434. if (classLoader != Thread.currentThread().getContextClassLoader()) {
  435. cls = forName(className, true, Thread.currentThread().getContextClassLoader());
  436. } else {
  437. throw e;
  438. }
  439. }
  440. cache.put(className, new WeakReference<Class>(cls));
  441. return cls;
  442. }
  443. }
  444. public static Constructor[] getConstructors(Class cls) {
  445. WeakReference<Constructor[]> ref = CLASS_CONSTRUCTOR_CACHE.get(cls);
  446. Constructor[] cns;
  447. if (ref != null && (cns = ref.get()) != null) {
  448. return cns;
  449. }
  450. else {
  451. CLASS_CONSTRUCTOR_CACHE.put(cls, new WeakReference<Constructor[]>(cns = cls.getConstructors()));
  452. return cns;
  453. }
  454. }
  455. public static String[] captureContructorAndResidual(char[] cs, int start, int offset) {
  456. int depth = 0;
  457. int end = start + offset;
  458. for (int i = start; i < end; i++) {
  459. switch (cs[i]) {
  460. case '(':
  461. depth++;
  462. continue;
  463. case ')':
  464. if (1 == depth--) {
  465. return new String[]{createStringTrimmed(cs, start, ++i - start), createStringTrimmed(cs, i, end - i)};
  466. }
  467. }
  468. }
  469. return new String[]{new String(cs, start, offset)};
  470. }
  471. public static Class boxPrimitive(Class cls) {
  472. if (cls == int.class || cls == Integer.class) {
  473. return Integer.class;
  474. }
  475. else if (cls == int[].class || cls == Integer[].class) {
  476. return Integer[].class;
  477. }
  478. else if (cls == char.class || cls == Character.class) {
  479. return Character.class;
  480. }
  481. else if (cls == char[].class || cls == Character[].class) {
  482. return Character[].class;
  483. }
  484. else if (cls == long.class || cls == Long.class) {
  485. return Long.class;
  486. }
  487. else if (cls == long[].class || cls == Long[].class) {
  488. return Long[].class;
  489. }
  490. else if (cls == short.class || cls == Short.class) {
  491. return Short.class;
  492. }
  493. else if (cls == short[].class || cls == Short[].class) {
  494. return Short[].class;
  495. }
  496. else if (cls == double.class || cls == Double.class) {
  497. return Double.class;
  498. }
  499. else if (cls == double[].class || cls == Double[].class) {
  500. return Double[].class;
  501. }
  502. else if (cls == float.class || cls == Float.class) {
  503. return Float.class;
  504. }
  505. else if (cls == float[].class || cls == Float[].class) {
  506. return Float[].class;
  507. }
  508. else if (cls == boolean.class || cls == Boolean.class) {
  509. return Boolean.class;
  510. }
  511. else if (cls == boolean[].class || cls == Boolean[].class) {
  512. return Boolean[].class;
  513. }
  514. else if (cls == byte.class || cls == Byte.class) {
  515. return Byte.class;
  516. }
  517. else if (cls == byte[].class || cls == Byte[].class) {
  518. return Byte[].class;
  519. }
  520. return cls;
  521. }
  522. public static Class unboxPrimitive(Class cls) {
  523. if (cls == Integer.class || cls == int.class) {
  524. return int.class;
  525. }
  526. else if (cls == Integer[].class || cls == int[].class) {
  527. return int[].class;
  528. }
  529. else if (cls == Long.class || cls == long.class) {
  530. return long.class;
  531. }
  532. else if (cls == Long[].class || cls == long[].class) {
  533. return long[].class;
  534. }
  535. else if (cls == Character.class || cls == char.class) {
  536. return char.class;
  537. }
  538. else if (cls == Character[].class || cls == char[].class) {
  539. return char[].class;
  540. }
  541. else if (cls == Short.class || cls == short.class) {
  542. return short.class;
  543. }
  544. else if (cls == Short[].class || cls == short[].class) {
  545. return short[].class;
  546. }
  547. else if (cls == Double.class || cls == double.class) {
  548. return double.class;
  549. }
  550. else if (cls == Double[].class || cls == double[].class) {
  551. return double[].class;
  552. }
  553. else if (cls == Float.class || cls == float.class) {
  554. return float.class;
  555. }
  556. else if (cls == Float[].class || cls == float[].class) {
  557. return float[].class;
  558. }
  559. else if (cls == Boolean.class || cls == boolean.class) {
  560. return boolean.class;
  561. }
  562. else if (cls == Boolean[].class || cls == boolean[].class) {
  563. return boolean[].class;
  564. }
  565. else if (cls == Byte.class || cls == byte.class) {
  566. return byte.class;
  567. }
  568. else if (cls == Byte[].class || cls == byte[].class) {
  569. return byte[].class;
  570. }
  571. return cls;
  572. }
  573. public static boolean containsCheck(Object compareTo, Object compareTest) {
  574. if (compareTo == null)
  575. return false;
  576. else if (compareTo instanceof String)
  577. return ((String) compareTo).contains(valueOf(compareTest));
  578. else if (compareTo instanceof Collection)
  579. return ((Collection) compareTo).contains(compareTest);
  580. else if (compareTo instanceof Map)
  581. return ((Map) compareTo).containsKey(compareTest);
  582. else if (compareTo.getClass().isArray()) {
  583. if (compareTo.getClass().getComponentType().isPrimitive())
  584. return containsCheckOnPrimitveArray(compareTo, compareTest);
  585. for (Object o : ((Object[]) compareTo)) {
  586. if (compareTest == null && o == null)
  587. return true;
  588. if ((Boolean) MathProcessor.doOperations(o, Operator.EQUAL, compareTest))
  589. return true;
  590. }
  591. }
  592. return false;
  593. }
  594. private static boolean containsCheckOnPrimitveArray(Object primitiveArray, Object compareTest) {
  595. Class<?> primitiveType = primitiveArray.getClass().getComponentType();
  596. if (primitiveType == boolean.class)
  597. return compareTest instanceof Boolean && containsCheckOnBooleanArray((boolean[]) primitiveArray, (Boolean) compareTest);
  598. if (primitiveType == int.class)
  599. return compareTest instanceof Integer && containsCheckOnIntArray((int[])primitiveArray, (Integer)compareTest);
  600. if (primitiveType == long.class)
  601. return compareTest instanceof Long && containsCheckOnLongArray((long[])primitiveArray, (Long)compareTest);
  602. if (primitiveType == double.class)
  603. return compareTest instanceof Double && containsCheckOnDoubleArray((double[]) primitiveArray, (Double) compareTest);
  604. if (primitiveType == float.class)
  605. return compareTest instanceof Float && containsCheckOnFloatArray((float[])primitiveArray, (Float)compareTest);
  606. if (primitiveType == char.class)
  607. return compareTest instanceof Character && containsCheckOnCharArray((char[])primitiveArray, (Character)compareTest);
  608. if (primitiveType == short.class)
  609. return compareTest instanceof Short && containsCheckOnShortArray((short[])primitiveArray, (Short)compareTest);
  610. if (primitiveType == byte.class)
  611. return compareTest instanceof Byte && containsCheckOnByteArray((byte[]) primitiveArray, (Byte) compareTest);
  612. return false;
  613. }
  614. private static boolean containsCheckOnBooleanArray(boolean[] array, Boolean compareTest) {
  615. boolean test = compareTest.booleanValue();
  616. for (boolean b : array) if (b == test) return true;
  617. return false;
  618. }
  619. private static boolean containsCheckOnIntArray(int[] array, Integer compareTest) {
  620. int test = compareTest.intValue();
  621. for (int i : array) if (i == test) return true;
  622. return false;
  623. }
  624. private static boolean containsCheckOnLongArray(long[] array, Long compareTest) {
  625. long test = compareTest.longValue();
  626. for (long l : array) if (l == test) return true;
  627. return false;
  628. }
  629. private static boolean containsCheckOnDoubleArray(double[] array, Double compareTest) {
  630. double test = compareTest.doubleValue();
  631. for (double d : array) if (d == test) return true;
  632. return false;
  633. }
  634. private static boolean containsCheckOnFloatArray(float[] array, Float compareTest) {
  635. float test = compareTest.floatValue();
  636. for (float f : array) if (f == test) return true;
  637. return false;
  638. }
  639. private static boolean containsCheckOnCharArray(char[] array, Character compareTest) {
  640. char test = compareTest.charValue();
  641. for (char c : array) if (c == test) return true;
  642. return false;
  643. }
  644. private static boolean containsCheckOnShortArray(short[] array, Short compareTest) {
  645. short test = compareTest.shortValue();
  646. for (short s : array) if (s == test) return true;
  647. return false;
  648. }
  649. private static boolean containsCheckOnByteArray(byte[] array, Byte compareTest) {
  650. byte test = compareTest.byteValue();
  651. for (byte b : array) if (b == test) return true;
  652. return false;
  653. }
  654. public static int createClassSignatureHash(Class declaring, Class[] sig) {
  655. int hash = 0;
  656. for (int i = 0; i < sig.length; i++) {
  657. if (sig[i] != null) {
  658. hash += ( sig[i].hashCode() * ( i * 2 + 3 ) );
  659. }
  660. }
  661. return hash + sig.length + declaring.hashCode();
  662. }
  663. /**
  664. * Replace escape sequences and return trim required.
  665. *
  666. * @param escapeStr -
  667. * @param pos -
  668. * @return -
  669. */
  670. public static int handleEscapeSequence(char[] escapeStr, int pos) {
  671. escapeStr[pos - 1] = 0;
  672. switch (escapeStr[pos]) {
  673. case '\\':
  674. escapeStr[pos] = '\\';
  675. return 1;
  676. case 'b':
  677. escapeStr[pos] = '\b';
  678. return 1;
  679. case 'f':
  680. escapeStr[pos] = '\f';
  681. return 1;
  682. case 't':
  683. escapeStr[pos] = '\t';
  684. return 1;
  685. case 'r':
  686. escapeStr[pos] = '\r';
  687. return 1;
  688. case 'n':
  689. escapeStr[pos] = '\n';
  690. return 1;
  691. case '\'':
  692. escapeStr[pos] = '\'';
  693. return 1;
  694. case '"':
  695. escapeStr[pos] = '\"';
  696. return 1;
  697. case 'u':
  698. //unicode
  699. int s = pos;
  700. if (s + 4 > escapeStr.length)
  701. throw new CompileException("illegal unicode escape sequence", escapeStr, pos);
  702. else {
  703. while (++pos - s != 5) {
  704. if ((escapeStr[pos] > ('0' - 1) && escapeStr[pos] < ('9' + 1)) ||
  705. (escapeStr[pos] > ('A' - 1) && escapeStr[pos] < ('F' + 1))) {
  706. }
  707. else {
  708. throw new CompileException("illegal unicode escape sequence", escapeStr, pos);
  709. }
  710. }
  711. escapeStr[s - 1] = (char) Integer.decode("0x" + new String(escapeStr, s + 1, 4)).intValue();
  712. escapeStr[s] = 0;
  713. escapeStr[s + 1] = 0;
  714. escapeStr[s + 2] = 0;
  715. escapeStr[s + 3] = 0;
  716. escapeStr[s + 4] = 0;
  717. return 5;
  718. }
  719. default:
  720. //octal
  721. s = pos;
  722. while (escapeStr[pos] >= '0' && escapeStr[pos] < '8') {
  723. if (pos != s && escapeStr[s] > '3') {
  724. escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
  725. escapeStr[s] = 0;
  726. escapeStr[s + 1] = 0;
  727. return 2;
  728. }
  729. else if ((pos - s) == 2) {
  730. escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
  731. escapeStr[s] = 0;
  732. escapeStr[s + 1] = 0;
  733. escapeStr[s + 2] = 0;
  734. return 3;
  735. }
  736. if (pos + 1 == escapeStr.length || (escapeStr[pos] < '0' || escapeStr[pos] > '7')) {
  737. escapeStr[s - 1] = (char) Integer.decode("0" + new String(escapeStr, s, pos - s + 1)).intValue();
  738. escapeStr[s] = 0;
  739. return 1;
  740. }
  741. pos++;
  742. }
  743. throw new CompileException("illegal escape sequence: " + escapeStr[pos], escapeStr, pos);
  744. }
  745. }
  746. public static char[] createShortFormOperativeAssignment(String name, char[] statement, int start, int offset, int operation) {
  747. if (operation == -1) {
  748. return statement;
  749. }
  750. char[] stmt;
  751. char op = 0;
  752. switch (operation) {
  753. case Operator.ADD:
  754. op = '+';
  755. break;
  756. case Operator.STR_APPEND:
  757. op = '#';
  758. break;
  759. case Operator.SUB:
  760. op = '-';
  761. break;
  762. case Operator.MULT:
  763. op = '*';
  764. break;
  765. case Operator.MOD:
  766. op = '%';
  767. break;
  768. case Operator.DIV:
  769. op = '/';
  770. break;
  771. case Operator.BW_AND:
  772. op = '&';
  773. break;
  774. case Operator.BW_OR:
  775. op = '|';
  776. break;
  777. case Operator.BW_SHIFT_LEFT:
  778. op = '\u00AB';
  779. break;
  780. case Operator.BW_SHIFT_RIGHT:
  781. op = '\u00BB';
  782. break;
  783. case Operator.BW_USHIFT_RIGHT:
  784. op = '\u00AC';
  785. break;
  786. }
  787. arraycopy(name.toCharArray(), 0, (stmt = new char[name.length() + offset + 1]), 0, name.length());
  788. stmt[name.length()] = op;
  789. arraycopy(statement, start, stmt, name.length() + 1, offset);
  790. return stmt;
  791. }
  792. public static ClassImportResolverFactory findClassImportResolverFactory(VariableResolverFactory factory, ParserContext pCtx) {
  793. if (factory == null) {
  794. throw new OptimizationFailure("unable to import classes. no variable resolver factory available.");
  795. }
  796. for (VariableResolverFactory v = factory; v != null; v = v.getNextFactory()) {
  797. if (v instanceof ClassImportResolverFactory) {
  798. return (ClassImportResolverFactory) v;
  799. }
  800. }
  801. return appendFactory(factory, new ClassImportResolverFactory(null, null, false));
  802. }
  803. public static Class findClass(VariableResolverFactory factory, String name, ParserContext pCtx) throws ClassNotFoundException {
  804. try {
  805. if (LITERALS.containsKey(name)) {
  806. return (Class) LITERALS.get(name);
  807. }
  808. else if (factory != null && factory.isResolveable(name)) {
  809. return (Class) factory.getVariableResolver(name).getValue();
  810. }
  811. else if (pCtx != null && pCtx.hasImport(name)) {
  812. return pCtx.getImport(name);
  813. }
  814. else {
  815. return createClass(name, pCtx);
  816. }
  817. }
  818. catch (ClassNotFoundException e) {
  819. throw e;
  820. }
  821. catch (Exception e) {
  822. throw new RuntimeException("class not found: " + name, e);
  823. }
  824. }
  825. public static char[] subsetTrimmed(char[] array, int start, int length) {
  826. if (length <= 0) {
  827. return new char[0];
  828. }
  829. int end = start + length;
  830. while (end > 0 && isWhitespace(array[end - 1])) {
  831. end--;
  832. }
  833. while (isWhitespace(array[start]) && start < end) {
  834. start++;
  835. }
  836. length = end - start;
  837. if (length == 0) {
  838. return new char[0];
  839. }
  840. return subset(array, start, length);
  841. }
  842. public static char[] subset(char[] array, int start, int length) {
  843. char[] newArray = new char[length];
  844. for (int i = 0; i < newArray.length; i++) {
  845. newArray[i] = array[i + start];
  846. }
  847. return newArray;
  848. }
  849. public static char[] subset(char[] array, int start) {
  850. char[] newArray = new char[array.length - start];
  851. for (int i = 0; i < newArray.length; i++) {
  852. newArray[i] = array[i + start];
  853. }
  854. return newArray;
  855. }
  856. private static final HashMap<Class, Integer> typeResolveMap = new HashMap<Class, Integer>();
  857. static {
  858. Map<Class, Integer> t = typeResolveMap;
  859. t.put(BigDecimal.class, DataTypes.BIG_DECIMAL);
  860. t.put(BigInteger.class, DataTypes.BIG_INTEGER);
  861. t.put(String.class, DataTypes.STRING);
  862. t.put(int.class, INTEGER);
  863. t.put(Integer.class, DataTypes.W_INTEGER);
  864. t.put(short.class, DataTypes.SHORT);
  865. t.put(Short.class, DataTypes.W_SHORT);
  866. t.put(float.class, DataTypes.FLOAT);
  867. t.put(Float.class, DataTypes.W_FLOAT);
  868. t.put(double.class, DOUBLE);
  869. t.put(Double.class, DataTypes.W_DOUBLE);
  870. t.put(long.class, LONG);
  871. t.put(Long.class, DataTypes.W_LONG);
  872. t.put(boolean.class, DataTypes.BOOLEAN);
  873. t.put(Boolean.class, DataTypes.W_BOOLEAN);
  874. t.put(byte.class, DataTypes.BYTE);
  875. t.put(Byte.class, DataTypes.W_BYTE);
  876. t.put(char.class, DataTypes.CHAR);
  877. t.put(Character.class, DataTypes.W_CHAR);
  878. t.put(BlankLiteral.class, DataTypes.EMPTY);
  879. }
  880. public static int resolveType(Object o) {
  881. if (o == null) return DataTypes.OBJECT;
  882. else return __resolveType(o.getClass());
  883. }
  884. private static final Map<Class, Integer> typeCodes = new HashMap<Class, Integer>(30, 0.5f);
  885. static {
  886. typeCodes.put(Integer.class, DataTypes.W_INTEGER);
  887. typeCodes.put(Double.class, DataTypes.W_DOUBLE);
  888. typeCodes.put(Boolean.class, DataTypes.W_BOOLEAN);
  889. typeCodes.put(String.class, DataTypes.STRING);
  890. typeCodes.put(Long.class, DataTypes.W_LONG);
  891. typeCodes.put(Short.class, DataTypes.W_SHORT);
  892. typeCodes.put(Float.class, DataTypes.W_FLOAT);
  893. typeCodes.put(Byte.class, DataTypes.W_BYTE);
  894. typeCodes.put(Character.class, DataTypes.W_CHAR);
  895. typeCodes.put(BigDecimal.class, DataTypes.BIG_DECIMAL);
  896. typeCodes.put(BigInteger.class, DataTypes.BIG_INTEGER);
  897. typeCodes.put(int.class, DataTypes.INTEGER);
  898. typeCodes.put(double.class, DataTypes.DOUBLE);
  899. typeCodes.put(boolean.class, DataTypes.BOOLEAN);
  900. typeCodes.put(long.class, DataTypes.LONG);
  901. typeCodes.put(short.class, DataTypes.SHORT);
  902. typeCodes.put(float.class, DataTypes.FLOAT);
  903. typeCodes.put(byte.class, DataTypes.BYTE);
  904. typeCodes.put(char.class, DataTypes.CHAR);
  905. typeCodes.put(BlankLiteral.class, DataTypes.EMPTY);
  906. }
  907. public static int __resolveType(Class cls) {
  908. Integer code = typeCodes.get(cls);
  909. if (code == null) {
  910. if (cls != null && Collection.class.isAssignableFrom(cls)) {
  911. return DataTypes.COLLECTION;
  912. }
  913. else {
  914. return DataTypes.OBJECT;
  915. }
  916. }
  917. return code;
  918. }
  919. public static boolean isNumericallyCoercible(Class target, Class parm) {
  920. Class boxedTarget = target.isPrimitive() ? boxPrimitive(target) : target;
  921. if (boxedTarget != null && Number.class.isAssignableFrom(target)) {
  922. if ((boxedTarget = parm.isPrimitive() ? boxPrimitive(parm) : parm) != null) {
  923. return Number.class.isAssignableFrom(boxedTarget);
  924. }
  925. }
  926. return false;
  927. }
  928. public static Object narrowType(final BigDecimal result, int returnTarget) {
  929. if (returnTarget == DataTypes.W_DOUBLE || result.scale() > 0) {
  930. return result.doubleValue();
  931. }
  932. else if (returnTarget == DataTypes.W_LONG || result.longValue() > Integer.MAX_VALUE) {
  933. return result.longValue();
  934. }
  935. else {
  936. return result.intValue();
  937. }
  938. }
  939. public static Method determineActualTargetMethod(Method method) {
  940. String name = method.getName();
  941. /**
  942. * Follow our way up the class heirarchy until we find the physical target method.
  943. */
  944. for (Class cls : method.getDeclaringClass().getInterfaces()) {
  945. for (Method meth : cls.getMethods()) {
  946. if (meth.getParameterTypes().length == 0 && name.equals(meth.getName())) {
  947. return meth;
  948. }
  949. }
  950. }
  951. return null;
  952. }
  953. public static int captureToNextTokenJunction(char[] expr, int cursor, int end, ParserContext pCtx) {
  954. while (cursor != expr.length) {
  955. switch (expr[cursor]) {
  956. case '{':
  957. case '(':
  958. return cursor;
  959. case '[':
  960. cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '[', pCtx) + 1;
  961. continue;
  962. default:
  963. if (isWhitespace(expr[cursor])) {
  964. return cursor;
  965. }
  966. cursor++;
  967. }
  968. }
  969. return cursor;
  970. }
  971. public static int nextNonBlank(char[] expr, int cursor) {
  972. if ((cursor + 1) >= expr.length) {
  973. throw new CompileException("unexpected end of statement", expr, cursor);
  974. }
  975. int i = cursor;
  976. while (i != expr.length && isWhitespace(expr[i])) i++;
  977. return i;
  978. }
  979. public static int skipWhitespace(char[] expr, int cursor) {
  980. // int line = 0;
  981. // int lastLineStart = 0;
  982. //
  983. // if (pCtx != null) {
  984. // line = pCtx.getLineCount();
  985. // lastLineStart = pCtx.getLineOffset();
  986. // }
  987. Skip:
  988. while (cursor != expr.length) {
  989. switch (expr[cursor]) {
  990. case '\n':
  991. case '\r':
  992. cursor++;
  993. continue;
  994. case '/':
  995. if (cursor + 1 != expr.length) {
  996. switch (expr[cursor + 1]) {
  997. case '/':
  998. expr[cursor++] = ' ';
  999. while (cursor != expr.length && expr[cursor] != '\n') expr[cursor++] = ' ';
  1000. if (cursor != expr.length) expr[cursor++] = ' ';
  1001. continue;
  1002. case '*':
  1003. int len = expr.length - 1;
  1004. expr[cursor++] = ' ';
  1005. while (cursor != len && !(expr[cursor] == '*' && expr[cursor + 1] == '/')) {
  1006. expr[cursor++] = ' ';
  1007. }
  1008. if (cursor != len) expr[cursor++] = expr[cursor++] = ' ';
  1009. continue;
  1010. default:
  1011. break Skip;
  1012. }
  1013. }
  1014. default:
  1015. if (!isWhitespace(expr[cursor])) break Skip;
  1016. }
  1017. cursor++;
  1018. }
  1019. return cursor;
  1020. }
  1021. public static boolean isStatementNotManuallyTerminated(char[] expr, int cursor) {
  1022. if (cursor >= expr.length) return false;
  1023. int c = cursor;
  1024. while (c != expr.length && isWhitespace(expr[c])) c++;
  1025. return !(c != expr.length && expr[c] == ';');
  1026. }
  1027. public static int captureToEOS(char[] expr, int cursor, int end, ParserContext pCtx) {
  1028. while (cursor != expr.length) {
  1029. switch (expr[cursor]) {
  1030. case '(':
  1031. case '[':
  1032. case '{':
  1033. if ((cursor = balancedCaptureWithLineAccounting(expr, cursor, end, expr[cursor], pCtx)) >= expr.length)
  1034. return cursor;
  1035. break;
  1036. case '"':
  1037. case '\'':
  1038. cursor = captureStringLiteral(expr[cursor], expr, cursor, expr.length);
  1039. break;
  1040. case ',':
  1041. case ';':
  1042. case '}':
  1043. return cursor;
  1044. }
  1045. cursor++;
  1046. }
  1047. return cursor;
  1048. }
  1049. /**
  1050. * From the specified cursor position, trim out any whitespace between the current position and the end of the
  1051. * last non-whitespace character.
  1052. *
  1053. * @param expr -
  1054. * @param start -
  1055. * @param pos - current position
  1056. * @return new position.
  1057. */
  1058. public static int trimLeft(char[] expr, int start, int pos) {
  1059. if (pos > expr.length) pos = expr.length;
  1060. while (pos != 0 && pos >= start && isWhitespace(expr[pos - 1])) pos--;
  1061. return pos;
  1062. }
  1063. /**
  1064. * From the specified cursor position, trim out any whitespace between the current position and beginning of the
  1065. * first non-whitespace character.
  1066. *
  1067. *
  1068. * @param expr -
  1069. * @param pos -
  1070. * @return -
  1071. */
  1072. public static int trimRight(char[] expr, int pos) {
  1073. while (pos != expr.length && isWhitespace(expr[pos])) pos++;
  1074. return pos;
  1075. }
  1076. public static char[] subArray(char[] expr, final int start, final int end) {
  1077. if (start >= end) return new char[0];
  1078. char[] newA = new char[end - start];
  1079. for (int i = 0; i != newA.length; i++) {
  1080. newA[i] = expr[i + start];
  1081. }
  1082. return newA;
  1083. }
  1084. /**
  1085. * This is an important aspect of the core parser tools. This method is used throughout the core parser
  1086. * and sub-lexical parsers to capture a balanced capture between opening and terminating tokens such as:
  1087. * <em>( [ { ' " </em>
  1088. * <br>
  1089. * <br>
  1090. * For example: ((foo + bar + (bar - foo)) * 20;<br>
  1091. * <br>
  1092. * <p/>
  1093. * If a balanced capture is performed from position 2, we get "(foo + bar + (bar - foo))" back.<br>
  1094. * If a balanced capture is performed from position 15, we get "(bar - foo)" back.<br>
  1095. * Etc.
  1096. *
  1097. * @param chars -
  1098. * @param start -
  1099. * @param type -
  1100. * @return -
  1101. */
  1102. public static int balancedCapture(char[] chars, int start, char type) {
  1103. return balancedCapture(chars, start, chars.length, type);
  1104. }
  1105. public static int balancedCapture(char[] chars, int start, int end, char type) {
  1106. int depth = 1;
  1107. char term = type;
  1108. switch (type) {
  1109. case '[':
  1110. term = ']';
  1111. break;
  1112. case '{':
  1113. term = '}';
  1114. break;
  1115. case '(':
  1116. term = ')';
  1117. break;
  1118. }
  1119. if (type == term) {
  1120. for (start++; start < end; start++) {
  1121. if (chars[start] == type) {
  1122. return start;
  1123. }
  1124. }
  1125. }
  1126. else {
  1127. for (start++; start < end; start++) {
  1128. if (start < end && chars[start] == '/') {
  1129. if (start + 1 == end) return start;
  1130. if (chars[start + 1] == '/') {
  1131. start++;
  1132. while (start < end && chars[start] != '\n') start++;
  1133. }
  1134. else if (chars[start + 1] == '*') {
  1135. start += 2;
  1136. SkipComment: while (start < end) {
  1137. switch (chars[start]) {
  1138. case '*':
  1139. if (start + 1 < end && chars[start + 1] == '/') {
  1140. break SkipComment;
  1141. }
  1142. case '\r':
  1143. case '\n':
  1144. break;
  1145. }
  1146. start++;
  1147. }
  1148. }
  1149. }
  1150. if (start == end) return start;
  1151. if (chars[start] == '\'' || chars[start] == '"') {
  1152. start = captureStringLiteral(chars[start], chars, start, end);
  1153. }
  1154. else if (chars[start] == type) {
  1155. depth++;
  1156. }
  1157. else if (chars[start] == term && --depth == 0) {
  1158. return start;
  1159. }
  1160. }
  1161. }
  1162. switch (type) {
  1163. case '[':
  1164. throw new CompileException("unbalanced braces [ ... ]", chars, start);
  1165. case '{':
  1166. throw new CompileException("unbalanced braces { ... }", chars, start);
  1167. case '(':
  1168. throw new CompileException("unbalanced braces ( ... )", chars, start);
  1169. default:
  1170. throw new CompileException("unterminated string literal", chars, start);
  1171. }
  1172. }
  1173. public static int balancedCaptureWithLineAccounting(char[] chars, int start, int end, char type, ParserContext pCtx) {
  1174. int depth = 1;
  1175. int st = start;
  1176. char term = type;
  1177. switch (type) {
  1178. case '[':
  1179. term = ']';
  1180. break;
  1181. case '{':
  1182. term = '}';
  1183. break;
  1184. case '(':
  1185. term = ')';
  1186. break;
  1187. }
  1188. if (type == term) {
  1189. for (start++; start != end; start++) {
  1190. if (chars[start] == type) {
  1191. return start;
  1192. }
  1193. }
  1194. }
  1195. else {
  1196. int lines = 0;
  1197. for (start++; start < end; start++) {
  1198. if (isWhitespace(chars[start])) {
  1199. switch (chars[start]) {
  1200. case '\r':
  1201. continue;
  1202. case '\n':
  1203. if (pCtx != null) pCtx.setLineOffset((short) start);
  1204. lines++;
  1205. }
  1206. }
  1207. else if (start < end && chars[start] == '/') {
  1208. if (start + 1 == end) return start;
  1209. if (chars[start + 1] == '/') {
  1210. start++;
  1211. while (start < end && chars[start] != '\n') start++;
  1212. }
  1213. else if (chars[start + 1] == '*') {
  1214. start += 2;
  1215. Skiploop:
  1216. while (start != end) {
  1217. switch (chars[start]) {
  1218. case '*':
  1219. if (start + 1 < end && chars[start + 1] == '/') {
  1220. break Skiploop;
  1221. }
  1222. case '\r':
  1223. case '\n':
  1224. if (pCtx != null) pCtx.setLineOffset((short) start);
  1225. lines++;
  1226. break;
  1227. }
  1228. start++;
  1229. }
  1230. }
  1231. }
  1232. if (start == end) return start;
  1233. if (chars[start] == '\'' || chars[start] == '"') {
  1234. start = captureStringLiteral(chars[start], chars, start, end);
  1235. }
  1236. else if (chars[start] == type) {
  1237. depth++;
  1238. }
  1239. else if (chars[start] == term && --depth == 0) {
  1240. if (pCtx != null) pCtx.incrementLineCount(lines);
  1241. return start;
  1242. }
  1243. }
  1244. }
  1245. switch (type) {
  1246. case '[':
  1247. throw new CompileException("unbalanced braces [ ... ]", chars, st);
  1248. case '{':
  1249. throw new CompileException("unbalanced braces { ... }", chars, st);
  1250. case '(':
  1251. throw new CompileException("unbalanced braces ( ... )", chars, st);
  1252. default:
  1253. throw new CompileException("unterminated string literal", chars, st);
  1254. }
  1255. }
  1256. public static String handleStringEscapes(char[] input) {
  1257. int escapes = 0;
  1258. for (int i = 0; i < input.length; i++) {
  1259. if (input[i] == '\\') {
  1260. escapes += handleEscapeSequence(input, ++i);
  1261. }
  1262. }
  1263. if (escapes == 0) return new String(input);
  1264. char[] processedEscapeString = new char[input.length - escapes];
  1265. int cursor = 0;
  1266. for (char aName : input) {
  1267. if (aName != 0) {
  1268. processedEscapeString[cursor++] = aName;
  1269. }
  1270. }
  1271. return new String(processedEscapeString);
  1272. }
  1273. public static int captureStringLiteral(final char type, final char[] expr, int cursor, int end) {
  1274. while (++cursor < end && expr[cursor] != type) {
  1275. if (expr[cursor] == '\\') cursor++;
  1276. }
  1277. if (cursor >= end || expr[cursor] != type) {
  1278. throw new CompileException("unterminated string literal", expr, cursor);
  1279. }
  1280. return cursor;
  1281. }
  1282. public static void parseWithExpressions(String nestParm, char[] block, int start, int offset,
  1283. Object ctx, VariableResolverFactory factory) {
  1284. /**
  1285. *
  1286. * MAINTENANCE NOTE: A COMPILING VERSION OF THIS CODE IS DUPLICATED IN: WithNode
  1287. *
  1288. */
  1289. int _st = start;
  1290. int _end = -1;
  1291. int end = start + offset;
  1292. int oper = -1;
  1293. String parm = "";
  1294. for (int i = start; i < end; i++) {
  1295. switch (block[i]) {
  1296. case '{':
  1297. case '[':
  1298. case '(':
  1299. case '\'':
  1300. case '"':
  1301. i = balancedCapture(block, i, end, block[i]);
  1302. continue;
  1303. case '/':
  1304. if (i < end && block[i + 1] == '/') {
  1305. while (i < end && block[i] != '\n') block[i++] = ' ';
  1306. if (parm == null) _st = i;
  1307. }
  1308. else if (i < end && block[i + 1] == '*') {
  1309. int len = end - 1;
  1310. while (i < len && !(block[i] == '*' && block[i + 1] == '/')) {
  1311. block[i++] = ' ';
  1312. }
  1313. block[i++] = ' ';
  1314. block[i++] = ' ';
  1315. if (parm == null) _st = i;
  1316. }
  1317. else if (i < end && block[i + 1] == '=') {
  1318. oper = Operator.DIV;
  1319. }
  1320. continue;
  1321. case '%':
  1322. case '*':
  1323. case '-':
  1324. case '+':
  1325. if (i + 1 < end && block[i + 1] == '=') {
  1326. oper = opLookup(block[i]);
  1327. }
  1328. continue;
  1329. case '=':
  1330. parm = new String(block, _st, i - _st - (oper != -1 ? 1 : 0)).trim();
  1331. _st = i + 1;
  1332. continue;
  1333. case ',':
  1334. if (_end == -1) _end = i;
  1335. if (parm == null) {
  1336. try {
  1337. if (nestParm == null) {
  1338. MVEL.eval(new String(block, _st, _end - _st), ctx, factory);
  1339. }
  1340. else {
  1341. MVEL.eval(new StringBuilder(nestParm).append('.')
  1342. .append(block, _st, _end - _st).toString(), ctx, factory);
  1343. }
  1344. }
  1345. catch (CompileException e) {
  1346. e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
  1347. e.setExpr(block);
  1348. throw e;
  1349. }
  1350. oper = -1;
  1351. _st = ++i;
  1352. }
  1353. else {
  1354. try {
  1355. if (oper != -1) {
  1356. if (nestParm == null) {
  1357. throw new CompileException("operative assignment not possible here", block, start);
  1358. }
  1359. String rewrittenExpr = new String(
  1360. createShortFormOperativeAssignment(nestParm + "." + parm, block, _st, _end - _st, oper));
  1361. MVEL.setProperty(ctx, parm, MVEL.eval(rewrittenExpr, ctx, factory));
  1362. }
  1363. else {
  1364. MVEL.setProperty(ctx, parm, MVEL.eval(block, _st, _end - _st, ctx, factory));
  1365. }
  1366. }
  1367. catch (CompileException e) {
  1368. e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
  1369. e.setExpr(block);
  1370. throw e;
  1371. }
  1372. parm = null;
  1373. oper = -1;
  1374. _st = ++i;
  1375. }
  1376. _end = -1;
  1377. break;
  1378. }
  1379. }
  1380. if (_st != (_end = end)) {
  1381. try {
  1382. if (parm == null || "".equals(parm)) {
  1383. if (nestParm == null) {
  1384. MVEL.eval(new String(block, _st, _end - _st), ctx, factory);
  1385. }
  1386. else {
  1387. MVEL.eval(new StringAppender(nestParm).append('.')
  1388. .append(block, _st, _end - _st).toString(), ctx, factory);
  1389. }
  1390. }
  1391. else {
  1392. if (oper != -1) {
  1393. if (nestParm == null) {
  1394. throw new CompileException("operative assignment not possible here", block, start);
  1395. }
  1396. String rewrittenExpr = new String(createShortFormOperativeAssignment(nestParm + "." + parm, block, _st, _end - _st, oper));
  1397. MVEL.setProperty(ctx, parm, MVEL.eval(rewrittenExpr, ctx, factory));
  1398. }
  1399. else {
  1400. MVEL.setProperty(ctx, parm, MVEL.eval(block, _st, end - _st, ctx, factory));
  1401. }
  1402. }
  1403. }
  1404. catch (CompileException e) {
  1405. e.setCursor(_st + (e.getCursor() - (e.getExpr().length - offset)));
  1406. e.setExpr(block);
  1407. throw e;
  1408. }
  1409. }
  1410. }
  1411. public static Object handleNumericConversion(final char[] val, int start, int offset) {
  1412. if (offset != 1 && val[start] == '0' && val[start + 1] != '.') {
  1413. if (!isDigit(val[start + offset - 1])) {
  1414. switch (val[start + offset - 1]) {
  1415. case 'L':
  1416. case 'l':
  1417. return Long.decode(new String(val, start, offset - 1));
  1418. case 'I':
  1419. return BigInteger.valueOf(Long.decode(new String(val, start, offset - 1)));
  1420. case 'B':
  1421. return BigDecimal.valueOf(Long.decode(new String(val, start, offset - 1)));
  1422. }
  1423. }
  1424. return Integer.decode(new String(val));
  1425. }
  1426. else if (!isDigit(val[start + offset - 1])) {
  1427. switch (val[start + offset - 1]) {
  1428. case 'l':

Large files files are truncated, but you can click here to view the full file