PageRenderTime 16ms CodeModel.GetById 2ms app.highlight 12ms RepoModel.GetById 0ms 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
 18package org.pentaho.reporting.libraries.formula.lvalues;
 19
 20import java.util.ArrayList;
 21
 22import org.pentaho.reporting.libraries.formula.EvaluationException;
 23import org.pentaho.reporting.libraries.formula.FormulaContext;
 24import org.pentaho.reporting.libraries.formula.operators.InfixOperator;
 25
 26/**
 27 * An term is a list of LValues connected by operators. For the sake of efficiency, this is not stored as tree. We store
 28 * the term as a list in the following format: (headValue)(OP value)* ...
 29 *
 30 * @author Thomas Morgner
 31 */
 32public class Term extends AbstractLValue
 33{
 34  private static final LValue[] EMPTY_L_VALUE = new LValue[0];
 35  private static final InfixOperator[] EMPTY_OPERATOR = new InfixOperator[0];
 36  private static final long serialVersionUID = -1854082494425470979L;
 37
 38  private LValue optimizedHeadValue;
 39  private LValue headValue;
 40  private ArrayList operators;
 41  private ArrayList operands;
 42  private InfixOperator[] operatorArray;
 43  private LValue[] operandsArray;
 44  private boolean initialized;
 45
 46  public Term(final LValue headValue)
 47  {
 48    if (headValue == null)
 49    {
 50      throw new NullPointerException();
 51    }
 52
 53    this.headValue = headValue;
 54  }
 55
 56  public TypeValuePair evaluate() throws EvaluationException
 57  {
 58    TypeValuePair result = optimizedHeadValue.evaluate();
 59    for (int i = 0; i < operandsArray.length; i++)
 60    {
 61      final LValue value = operandsArray[i];
 62      final InfixOperator op = operatorArray[i];
 63      result = op.evaluate(getContext(), result, value.evaluate());
 64    }
 65    return result;
 66  }
 67
 68  public void add(final InfixOperator operator, final LValue operand)
 69  {
 70    if (operator == null)
 71    {
 72      throw new NullPointerException();
 73    }
 74    if (operand == null)
 75    {
 76      throw new NullPointerException();
 77    }
 78
 79    if (operands == null || operators == null)
 80    {
 81      this.operands = new ArrayList();
 82      this.operators = new ArrayList();
 83    }
 84
 85    operands.add(operand);
 86    operators.add(operator);
 87    initialized = false;
 88  }
 89
 90  public void initialize(final FormulaContext context) throws EvaluationException
 91  {
 92    super.initialize(context);
 93    if (operands == null || operators == null)
 94    {
 95      this.optimizedHeadValue = headValue;
 96      this.optimizedHeadValue.initialize(context);
 97      this.operandsArray = EMPTY_L_VALUE;
 98      this.operatorArray = EMPTY_OPERATOR;
 99      return;
100    }
101
102    if (initialized)
103    {
104      optimizedHeadValue.initialize(context);
105      for (int i = 0; i < operandsArray.length; i++)
106      {
107        final LValue lValue = operandsArray[i];
108        lValue.initialize(context);
109      }
110      return;
111    }
112
113    optimize();
114    this.optimizedHeadValue.initialize(context);
115    for (int i = 0; i < operandsArray.length; i++)
116    {
117      final LValue value = operandsArray[i];
118      value.initialize(context);
119    }
120    initialized = true;
121  }
122
123  private void optimize()
124  {
125    if (operands == null || operators == null)
126    {
127      this.optimizedHeadValue = headValue;
128      this.operandsArray = EMPTY_L_VALUE;
129      this.operatorArray = EMPTY_OPERATOR;
130      return;
131    }
132    final ArrayList operators = (ArrayList) this.operators.clone();
133    final ArrayList operands = (ArrayList) this.operands.clone();
134    this.optimizedHeadValue = headValue;
135
136    while (true)
137    {
138      // now start to optimize everything.
139      // first, search the operator with the highest priority..
140      final InfixOperator op = (InfixOperator) operators.get(0);
141      int level = op.getLevel();
142      boolean moreThanOne = false;
143      for (int i = 1; i < operators.size(); i++)
144      {
145        final InfixOperator operator = (InfixOperator) operators.get(i);
146        final int opLevel = operator.getLevel();
147        if (opLevel != level)
148        {
149          moreThanOne = true;
150          level = Math.min(opLevel, level);
151        }
152      }
153
154      if (moreThanOne == false)
155      {
156        // No need to optimize the operators ..
157        break;
158      }
159
160      // There are at least two op-levels in this term.
161      Term subTerm = null;
162      for (int i = 0; i < operators.size(); i++)
163      {
164        final InfixOperator operator = (InfixOperator) operators.get(i);
165        if (operator.getLevel() != level)
166        {
167          subTerm = null;
168          continue;
169        }
170
171        if (subTerm == null)
172        {
173          if (i == 0)
174          {
175            subTerm = new Term(optimizedHeadValue);
176            optimizedHeadValue = subTerm;
177          }
178          else
179          {
180            final LValue lval = (LValue) operands.get(i - 1);
181            subTerm = new Term(lval);
182            operands.set(i - 1, subTerm);
183          }
184        }
185
186        // OK, now a term exists, and we should join it.
187        final LValue operand = (LValue) operands.get(i);
188        subTerm.add(operator, operand);
189        operands.remove(i);
190        operators.remove(i);
191        // Rollback the current index ..
192        //noinspection AssignmentToForLoopParameter
193        i -= 1;
194      }
195    }
196
197    this.operatorArray = (InfixOperator[])
198        operators.toArray(new InfixOperator[operators.size()]);
199    this.operandsArray = (LValue[])
200        operands.toArray(new LValue[operands.size()]);
201  }
202
203  /**
204   * Returns any dependent lvalues (parameters and operands, mostly).
205   *
206   * @return
207   */
208  public LValue[] getChildValues()
209  {
210    if (operandsArray == null)
211    {
212      optimize();
213    }
214    final LValue[] values = new LValue[operandsArray.length + 1];
215    values[0] = headValue;
216    System.arraycopy(operandsArray, 0, values, 1, operandsArray.length);
217    return values;
218  }
219
220
221  public String toString()
222  {
223    final StringBuffer b = new StringBuffer(100);
224
225    b.append('(');
226    b.append(headValue);
227    if (operands != null && operators != null)
228    {
229      for (int i = 0; i < operands.size(); i++)
230      {
231        final InfixOperator op = (InfixOperator) operators.get(i);
232        final LValue value = (LValue) operands.get(i);
233        b.append(op);
234        b.append(value);
235      }
236    }
237    b.append(')');
238//
239//    b.append(";OPTIMIZED(");
240//    b.append(optimizedHeadValue);
241//    if (operandsArray != null && operatorArray != null)
242//    {
243//      for (int i = 0; i < operandsArray.length; i++)
244//      {
245//        final InfixOperator op = operatorArray[i];
246//        final LValue value = operandsArray[i];
247//        b.append(op);
248//        b.append(value);
249//      }
250//    }
251//    b.append(")");
252
253    return b.toString();
254  }
255
256  /**
257   * Checks whether the LValue is constant. Constant lvalues always return the same value.
258   *
259   * @return
260   */
261  public boolean isConstant()
262  {
263    if (headValue.isConstant() == false)
264    {
265      return false;
266    }
267
268    for (int i = 0; i < operands.size(); i++)
269    {
270      final LValue value = (LValue) operands.get(i);
271      if (value.isConstant() == false)
272      {
273        return false;
274      }
275    }
276    return true;
277  }
278
279  public Object clone() throws CloneNotSupportedException
280  {
281    final Term o = (Term) super.clone();
282    if (operands != null)
283    {
284      o.operands = (ArrayList) operands.clone();
285    }
286    if (operators != null)
287    {
288      o.operators = (ArrayList) operators.clone();
289    }
290    o.headValue = (LValue) headValue.clone();
291    o.optimizedHeadValue = null;
292    o.operandsArray = null;
293    o.operatorArray = null;
294    o.initialized = false;
295    return o;
296  }
297
298  public LValue[] getOperands()
299  {
300    return (LValue[]) operands.toArray(new LValue[operands.size()]);
301  }
302
303  public InfixOperator[] getOperators()
304  {
305    return (InfixOperator[]) operators.toArray(new InfixOperator[operators.size()]);
306  }
307
308  public LValue getHeadValue()
309  {
310    return headValue;
311  }
312
313  /**
314   * Allows access to the post optimized head value note that without the optimization, it's difficult to traverse
315   * libformula's object model.
316   *
317   * @return optimized head value
318   */
319  public LValue getOptimizedHeadValue()
320  {
321    return optimizedHeadValue;
322  }
323//
324//  /**
325//   * Allows access to the post optimized operator array
326//   *
327//   * @return optimized operator array
328//   */
329//  public InfixOperator[] getOptimizedOperators()
330//  {
331//    return operatorArray;
332//  }
333//
334//  /**
335//   * Allows access to the post optimized operand array
336//   *
337//   * @return optimized operand array
338//   */
339//  public LValue[] getOptimizedOperands()
340//  {
341//    return operandsArray;
342//  }
343
344  public ParsePosition getParsePosition()
345  {
346    final ParsePosition parsePosition = super.getParsePosition();
347    if (parsePosition == null)
348    {
349      final int startColumn = headValue.getParsePosition().getStartColumn();
350      final int startLine = headValue.getParsePosition().getStartLine();
351      final ParsePosition lastParsePos =
352          operandsArray[operandsArray.length - 1].getParsePosition();
353      final int endColumn = lastParsePos.getEndColumn();
354      final int endLine = lastParsePos.getEndLine();
355      setParsePosition(new ParsePosition(startLine, startColumn, endLine, endColumn));
356    }
357    return super.getParsePosition();
358  }
359}