/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
- /*
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
- * Foundation.
- *
- * You should have received a copy of the GNU Lesser General Public License along with this
- * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
- * or from the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * Copyright (c) 2006 - 2009 Pentaho Corporation and Contributors. All rights reserved.
- */
- package org.pentaho.reporting.libraries.formula.lvalues;
- import java.util.ArrayList;
- import org.pentaho.reporting.libraries.formula.EvaluationException;
- import org.pentaho.reporting.libraries.formula.FormulaContext;
- import org.pentaho.reporting.libraries.formula.operators.InfixOperator;
- /**
- * An term is a list of LValues connected by operators. For the sake of efficiency, this is not stored as tree. We store
- * the term as a list in the following format: (headValue)(OP value)* ...
- *
- * @author Thomas Morgner
- */
- public class Term extends AbstractLValue
- {
- private static final LValue[] EMPTY_L_VALUE = new LValue[0];
- private static final InfixOperator[] EMPTY_OPERATOR = new InfixOperator[0];
- private static final long serialVersionUID = -1854082494425470979L;
- private LValue optimizedHeadValue;
- private LValue headValue;
- private ArrayList operators;
- private ArrayList operands;
- private InfixOperator[] operatorArray;
- private LValue[] operandsArray;
- private boolean initialized;
- public Term(final LValue headValue)
- {
- if (headValue == null)
- {
- throw new NullPointerException();
- }
- this.headValue = headValue;
- }
- public TypeValuePair evaluate() throws EvaluationException
- {
- TypeValuePair result = optimizedHeadValue.evaluate();
- for (int i = 0; i < operandsArray.length; i++)
- {
- final LValue value = operandsArray[i];
- final InfixOperator op = operatorArray[i];
- result = op.evaluate(getContext(), result, value.evaluate());
- }
- return result;
- }
- public void add(final InfixOperator operator, final LValue operand)
- {
- if (operator == null)
- {
- throw new NullPointerException();
- }
- if (operand == null)
- {
- throw new NullPointerException();
- }
- if (operands == null || operators == null)
- {
- this.operands = new ArrayList();
- this.operators = new ArrayList();
- }
- operands.add(operand);
- operators.add(operator);
- initialized = false;
- }
- public void initialize(final FormulaContext context) throws EvaluationException
- {
- super.initialize(context);
- if (operands == null || operators == null)
- {
- this.optimizedHeadValue = headValue;
- this.optimizedHeadValue.initialize(context);
- this.operandsArray = EMPTY_L_VALUE;
- this.operatorArray = EMPTY_OPERATOR;
- return;
- }
- if (initialized)
- {
- optimizedHeadValue.initialize(context);
- for (int i = 0; i < operandsArray.length; i++)
- {
- final LValue lValue = operandsArray[i];
- lValue.initialize(context);
- }
- return;
- }
- optimize();
- this.optimizedHeadValue.initialize(context);
- for (int i = 0; i < operandsArray.length; i++)
- {
- final LValue value = operandsArray[i];
- value.initialize(context);
- }
- initialized = true;
- }
- private void optimize()
- {
- if (operands == null || operators == null)
- {
- this.optimizedHeadValue = headValue;
- this.operandsArray = EMPTY_L_VALUE;
- this.operatorArray = EMPTY_OPERATOR;
- return;
- }
- final ArrayList operators = (ArrayList) this.operators.clone();
- final ArrayList operands = (ArrayList) this.operands.clone();
- this.optimizedHeadValue = headValue;
- while (true)
- {
- // now start to optimize everything.
- // first, search the operator with the highest priority..
- final InfixOperator op = (InfixOperator) operators.get(0);
- int level = op.getLevel();
- boolean moreThanOne = false;
- for (int i = 1; i < operators.size(); i++)
- {
- final InfixOperator operator = (InfixOperator) operators.get(i);
- final int opLevel = operator.getLevel();
- if (opLevel != level)
- {
- moreThanOne = true;
- level = Math.min(opLevel, level);
- }
- }
- if (moreThanOne == false)
- {
- // No need to optimize the operators ..
- break;
- }
- // There are at least two op-levels in this term.
- Term subTerm = null;
- for (int i = 0; i < operators.size(); i++)
- {
- final InfixOperator operator = (InfixOperator) operators.get(i);
- if (operator.getLevel() != level)
- {
- subTerm = null;
- continue;
- }
- if (subTerm == null)
- {
- if (i == 0)
- {
- subTerm = new Term(optimizedHeadValue);
- optimizedHeadValue = subTerm;
- }
- else
- {
- final LValue lval = (LValue) operands.get(i - 1);
- subTerm = new Term(lval);
- operands.set(i - 1, subTerm);
- }
- }
- // OK, now a term exists, and we should join it.
- final LValue operand = (LValue) operands.get(i);
- subTerm.add(operator, operand);
- operands.remove(i);
- operators.remove(i);
- // Rollback the current index ..
- //noinspection AssignmentToForLoopParameter
- i -= 1;
- }
- }
- this.operatorArray = (InfixOperator[])
- operators.toArray(new InfixOperator[operators.size()]);
- this.operandsArray = (LValue[])
- operands.toArray(new LValue[operands.size()]);
- }
- /**
- * Returns any dependent lvalues (parameters and operands, mostly).
- *
- * @return
- */
- public LValue[] getChildValues()
- {
- if (operandsArray == null)
- {
- optimize();
- }
- final LValue[] values = new LValue[operandsArray.length + 1];
- values[0] = headValue;
- System.arraycopy(operandsArray, 0, values, 1, operandsArray.length);
- return values;
- }
- public String toString()
- {
- final StringBuffer b = new StringBuffer(100);
- b.append('(');
- b.append(headValue);
- if (operands != null && operators != null)
- {
- for (int i = 0; i < operands.size(); i++)
- {
- final InfixOperator op = (InfixOperator) operators.get(i);
- final LValue value = (LValue) operands.get(i);
- b.append(op);
- b.append(value);
- }
- }
- b.append(')');
- //
- // b.append(";OPTIMIZED(");
- // b.append(optimizedHeadValue);
- // if (operandsArray != null && operatorArray != null)
- // {
- // for (int i = 0; i < operandsArray.length; i++)
- // {
- // final InfixOperator op = operatorArray[i];
- // final LValue value = operandsArray[i];
- // b.append(op);
- // b.append(value);
- // }
- // }
- // b.append(")");
- return b.toString();
- }
- /**
- * Checks whether the LValue is constant. Constant lvalues always return the same value.
- *
- * @return
- */
- public boolean isConstant()
- {
- if (headValue.isConstant() == false)
- {
- return false;
- }
- for (int i = 0; i < operands.size(); i++)
- {
- final LValue value = (LValue) operands.get(i);
- if (value.isConstant() == false)
- {
- return false;
- }
- }
- return true;
- }
- public Object clone() throws CloneNotSupportedException
- {
- final Term o = (Term) super.clone();
- if (operands != null)
- {
- o.operands = (ArrayList) operands.clone();
- }
- if (operators != null)
- {
- o.operators = (ArrayList) operators.clone();
- }
- o.headValue = (LValue) headValue.clone();
- o.optimizedHeadValue = null;
- o.operandsArray = null;
- o.operatorArray = null;
- o.initialized = false;
- return o;
- }
- public LValue[] getOperands()
- {
- return (LValue[]) operands.toArray(new LValue[operands.size()]);
- }
- public InfixOperator[] getOperators()
- {
- return (InfixOperator[]) operators.toArray(new InfixOperator[operators.size()]);
- }
- public LValue getHeadValue()
- {
- return headValue;
- }
- /**
- * Allows access to the post optimized head value note that without the optimization, it's difficult to traverse
- * libformula's object model.
- *
- * @return optimized head value
- */
- public LValue getOptimizedHeadValue()
- {
- return optimizedHeadValue;
- }
- //
- // /**
- // * Allows access to the post optimized operator array
- // *
- // * @return optimized operator array
- // */
- // public InfixOperator[] getOptimizedOperators()
- // {
- // return operatorArray;
- // }
- //
- // /**
- // * Allows access to the post optimized operand array
- // *
- // * @return optimized operand array
- // */
- // public LValue[] getOptimizedOperands()
- // {
- // return operandsArray;
- // }
- public ParsePosition getParsePosition()
- {
- final ParsePosition parsePosition = super.getParsePosition();
- if (parsePosition == null)
- {
- final int startColumn = headValue.getParsePosition().getStartColumn();
- final int startLine = headValue.getParsePosition().getStartLine();
- final ParsePosition lastParsePos =
- operandsArray[operandsArray.length - 1].getParsePosition();
- final int endColumn = lastParsePos.getEndColumn();
- final int endLine = lastParsePos.getEndLine();
- setParsePosition(new ParsePosition(startLine, startColumn, endLine, endColumn));
- }
- return super.getParsePosition();
- }
- }