PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/mvel/mvel
Java | 2259 lines | 2054 code | 174 blank | 31 comment | 446 complexity | c8ba485665d937261d01740cb3abc4d9 MD5 | raw file
Possible License(s): Apache-2.0

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

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

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