PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/libformula-1.1.3/source/org/pentaho/reporting/libraries/formula/lvalues/Term.java

#
Java | 359 lines | 246 code | 34 blank | 79 comment | 53 complexity | 3b6a90a60471cb4d9e33523e2bb17b04 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * This program is free software; you can redistribute it and/or modify it under the
  3. * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
  4. * Foundation.
  5. *
  6. * You should have received a copy of the GNU Lesser General Public License along with this
  7. * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
  8. * or from the Free Software Foundation, Inc.,
  9. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  12. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU Lesser General Public License for more details.
  14. *
  15. * Copyright (c) 2006 - 2009 Pentaho Corporation and Contributors. All rights reserved.
  16. */
  17. package org.pentaho.reporting.libraries.formula.lvalues;
  18. import java.util.ArrayList;
  19. import org.pentaho.reporting.libraries.formula.EvaluationException;
  20. import org.pentaho.reporting.libraries.formula.FormulaContext;
  21. import org.pentaho.reporting.libraries.formula.operators.InfixOperator;
  22. /**
  23. * An term is a list of LValues connected by operators. For the sake of efficiency, this is not stored as tree. We store
  24. * the term as a list in the following format: (headValue)(OP value)* ...
  25. *
  26. * @author Thomas Morgner
  27. */
  28. public class Term extends AbstractLValue
  29. {
  30. private static final LValue[] EMPTY_L_VALUE = new LValue[0];
  31. private static final InfixOperator[] EMPTY_OPERATOR = new InfixOperator[0];
  32. private static final long serialVersionUID = -1854082494425470979L;
  33. private LValue optimizedHeadValue;
  34. private LValue headValue;
  35. private ArrayList operators;
  36. private ArrayList operands;
  37. private InfixOperator[] operatorArray;
  38. private LValue[] operandsArray;
  39. private boolean initialized;
  40. public Term(final LValue headValue)
  41. {
  42. if (headValue == null)
  43. {
  44. throw new NullPointerException();
  45. }
  46. this.headValue = headValue;
  47. }
  48. public TypeValuePair evaluate() throws EvaluationException
  49. {
  50. TypeValuePair result = optimizedHeadValue.evaluate();
  51. for (int i = 0; i < operandsArray.length; i++)
  52. {
  53. final LValue value = operandsArray[i];
  54. final InfixOperator op = operatorArray[i];
  55. result = op.evaluate(getContext(), result, value.evaluate());
  56. }
  57. return result;
  58. }
  59. public void add(final InfixOperator operator, final LValue operand)
  60. {
  61. if (operator == null)
  62. {
  63. throw new NullPointerException();
  64. }
  65. if (operand == null)
  66. {
  67. throw new NullPointerException();
  68. }
  69. if (operands == null || operators == null)
  70. {
  71. this.operands = new ArrayList();
  72. this.operators = new ArrayList();
  73. }
  74. operands.add(operand);
  75. operators.add(operator);
  76. initialized = false;
  77. }
  78. public void initialize(final FormulaContext context) throws EvaluationException
  79. {
  80. super.initialize(context);
  81. if (operands == null || operators == null)
  82. {
  83. this.optimizedHeadValue = headValue;
  84. this.optimizedHeadValue.initialize(context);
  85. this.operandsArray = EMPTY_L_VALUE;
  86. this.operatorArray = EMPTY_OPERATOR;
  87. return;
  88. }
  89. if (initialized)
  90. {
  91. optimizedHeadValue.initialize(context);
  92. for (int i = 0; i < operandsArray.length; i++)
  93. {
  94. final LValue lValue = operandsArray[i];
  95. lValue.initialize(context);
  96. }
  97. return;
  98. }
  99. optimize();
  100. this.optimizedHeadValue.initialize(context);
  101. for (int i = 0; i < operandsArray.length; i++)
  102. {
  103. final LValue value = operandsArray[i];
  104. value.initialize(context);
  105. }
  106. initialized = true;
  107. }
  108. private void optimize()
  109. {
  110. if (operands == null || operators == null)
  111. {
  112. this.optimizedHeadValue = headValue;
  113. this.operandsArray = EMPTY_L_VALUE;
  114. this.operatorArray = EMPTY_OPERATOR;
  115. return;
  116. }
  117. final ArrayList operators = (ArrayList) this.operators.clone();
  118. final ArrayList operands = (ArrayList) this.operands.clone();
  119. this.optimizedHeadValue = headValue;
  120. while (true)
  121. {
  122. // now start to optimize everything.
  123. // first, search the operator with the highest priority..
  124. final InfixOperator op = (InfixOperator) operators.get(0);
  125. int level = op.getLevel();
  126. boolean moreThanOne = false;
  127. for (int i = 1; i < operators.size(); i++)
  128. {
  129. final InfixOperator operator = (InfixOperator) operators.get(i);
  130. final int opLevel = operator.getLevel();
  131. if (opLevel != level)
  132. {
  133. moreThanOne = true;
  134. level = Math.min(opLevel, level);
  135. }
  136. }
  137. if (moreThanOne == false)
  138. {
  139. // No need to optimize the operators ..
  140. break;
  141. }
  142. // There are at least two op-levels in this term.
  143. Term subTerm = null;
  144. for (int i = 0; i < operators.size(); i++)
  145. {
  146. final InfixOperator operator = (InfixOperator) operators.get(i);
  147. if (operator.getLevel() != level)
  148. {
  149. subTerm = null;
  150. continue;
  151. }
  152. if (subTerm == null)
  153. {
  154. if (i == 0)
  155. {
  156. subTerm = new Term(optimizedHeadValue);
  157. optimizedHeadValue = subTerm;
  158. }
  159. else
  160. {
  161. final LValue lval = (LValue) operands.get(i - 1);
  162. subTerm = new Term(lval);
  163. operands.set(i - 1, subTerm);
  164. }
  165. }
  166. // OK, now a term exists, and we should join it.
  167. final LValue operand = (LValue) operands.get(i);
  168. subTerm.add(operator, operand);
  169. operands.remove(i);
  170. operators.remove(i);
  171. // Rollback the current index ..
  172. //noinspection AssignmentToForLoopParameter
  173. i -= 1;
  174. }
  175. }
  176. this.operatorArray = (InfixOperator[])
  177. operators.toArray(new InfixOperator[operators.size()]);
  178. this.operandsArray = (LValue[])
  179. operands.toArray(new LValue[operands.size()]);
  180. }
  181. /**
  182. * Returns any dependent lvalues (parameters and operands, mostly).
  183. *
  184. * @return
  185. */
  186. public LValue[] getChildValues()
  187. {
  188. if (operandsArray == null)
  189. {
  190. optimize();
  191. }
  192. final LValue[] values = new LValue[operandsArray.length + 1];
  193. values[0] = headValue;
  194. System.arraycopy(operandsArray, 0, values, 1, operandsArray.length);
  195. return values;
  196. }
  197. public String toString()
  198. {
  199. final StringBuffer b = new StringBuffer(100);
  200. b.append('(');
  201. b.append(headValue);
  202. if (operands != null && operators != null)
  203. {
  204. for (int i = 0; i < operands.size(); i++)
  205. {
  206. final InfixOperator op = (InfixOperator) operators.get(i);
  207. final LValue value = (LValue) operands.get(i);
  208. b.append(op);
  209. b.append(value);
  210. }
  211. }
  212. b.append(')');
  213. //
  214. // b.append(";OPTIMIZED(");
  215. // b.append(optimizedHeadValue);
  216. // if (operandsArray != null && operatorArray != null)
  217. // {
  218. // for (int i = 0; i < operandsArray.length; i++)
  219. // {
  220. // final InfixOperator op = operatorArray[i];
  221. // final LValue value = operandsArray[i];
  222. // b.append(op);
  223. // b.append(value);
  224. // }
  225. // }
  226. // b.append(")");
  227. return b.toString();
  228. }
  229. /**
  230. * Checks whether the LValue is constant. Constant lvalues always return the same value.
  231. *
  232. * @return
  233. */
  234. public boolean isConstant()
  235. {
  236. if (headValue.isConstant() == false)
  237. {
  238. return false;
  239. }
  240. for (int i = 0; i < operands.size(); i++)
  241. {
  242. final LValue value = (LValue) operands.get(i);
  243. if (value.isConstant() == false)
  244. {
  245. return false;
  246. }
  247. }
  248. return true;
  249. }
  250. public Object clone() throws CloneNotSupportedException
  251. {
  252. final Term o = (Term) super.clone();
  253. if (operands != null)
  254. {
  255. o.operands = (ArrayList) operands.clone();
  256. }
  257. if (operators != null)
  258. {
  259. o.operators = (ArrayList) operators.clone();
  260. }
  261. o.headValue = (LValue) headValue.clone();
  262. o.optimizedHeadValue = null;
  263. o.operandsArray = null;
  264. o.operatorArray = null;
  265. o.initialized = false;
  266. return o;
  267. }
  268. public LValue[] getOperands()
  269. {
  270. return (LValue[]) operands.toArray(new LValue[operands.size()]);
  271. }
  272. public InfixOperator[] getOperators()
  273. {
  274. return (InfixOperator[]) operators.toArray(new InfixOperator[operators.size()]);
  275. }
  276. public LValue getHeadValue()
  277. {
  278. return headValue;
  279. }
  280. /**
  281. * Allows access to the post optimized head value note that without the optimization, it's difficult to traverse
  282. * libformula's object model.
  283. *
  284. * @return optimized head value
  285. */
  286. public LValue getOptimizedHeadValue()
  287. {
  288. return optimizedHeadValue;
  289. }
  290. //
  291. // /**
  292. // * Allows access to the post optimized operator array
  293. // *
  294. // * @return optimized operator array
  295. // */
  296. // public InfixOperator[] getOptimizedOperators()
  297. // {
  298. // return operatorArray;
  299. // }
  300. //
  301. // /**
  302. // * Allows access to the post optimized operand array
  303. // *
  304. // * @return optimized operand array
  305. // */
  306. // public LValue[] getOptimizedOperands()
  307. // {
  308. // return operandsArray;
  309. // }
  310. public ParsePosition getParsePosition()
  311. {
  312. final ParsePosition parsePosition = super.getParsePosition();
  313. if (parsePosition == null)
  314. {
  315. final int startColumn = headValue.getParsePosition().getStartColumn();
  316. final int startLine = headValue.getParsePosition().getStartLine();
  317. final ParsePosition lastParsePos =
  318. operandsArray[operandsArray.length - 1].getParsePosition();
  319. final int endColumn = lastParsePos.getEndColumn();
  320. final int endLine = lastParsePos.getEndLine();
  321. setParsePosition(new ParsePosition(startLine, startColumn, endLine, endColumn));
  322. }
  323. return super.getParsePosition();
  324. }
  325. }