PageRenderTime 56ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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