Package org.formulacompiler.compiler.internal.model.interpreter

Source Code of org.formulacompiler.compiler.internal.model.interpreter.InterpretedNumericType_Base

/*
* Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
* All rights reserved.
*
* This file is part of the Abacus Formula Compiler (AFC).
*
* For commercial licensing, please contact sales(at)formulacompiler.com.
*
* AFC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AFC 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AFC.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.formulacompiler.compiler.internal.model.interpreter;

import java.text.ParseException;
import java.util.List;

import org.formulacompiler.compiler.Function;
import org.formulacompiler.compiler.NumericType;
import org.formulacompiler.compiler.Operator;
import org.formulacompiler.compiler.internal.NumericTypeImpl;
import org.formulacompiler.compiler.internal.expressions.ArrayDescriptor;
import org.formulacompiler.compiler.internal.expressions.ExpressionNode;
import org.formulacompiler.compiler.internal.expressions.ExpressionNodeForArrayReference;
import org.formulacompiler.compiler.internal.expressions.ExpressionNodeForConstantValue;
import org.formulacompiler.runtime.ComputationMode;
import org.formulacompiler.runtime.FormulaException;
import org.formulacompiler.runtime.NotAvailableException;
import org.formulacompiler.runtime.internal.Environment;
import org.formulacompiler.runtime.internal.Runtime_v2;


abstract class InterpretedNumericType_Base
{
  private final NumericTypeImpl num;
  private final ComputationMode computationMode;


  InterpretedNumericType_Base( NumericType _type, ComputationMode _mode, Environment _env )
  {
    super();
    this.num = (NumericTypeImpl) _type;
    this.computationMode = _mode;
  }


  public abstract Object adjustConstantValue( Object _value );


  protected final int compare( Object _a, Object _b ) throws InterpreterException
  {
    if (_a instanceof String) {
      if (_b instanceof String || null == _b) {
        return toString( _a ).compareToIgnoreCase( toString( _b ) );
      }
      else {
        return +1; // String always greater than number in Excel.
      }
    }
    else if (_b instanceof String) {
      if (null == _a) {
        return ((String) _b).length() == 0 ? 0 : -1;
      }
      else {
        return -1; // Number always less than string in Excel.
      }
    }
    else {
      return compareNumerically( _a, _b );
    }
  }

  protected abstract int compareNumerically( Object _a, Object _b );


  public final Number zero()
  {
    return this.num.getZero();
  }

  public final Number minValue()
  {
    return this.num.getMinValue();
  }

  public final Number maxValue()
  {
    return this.num.getMaxValue();
  }


  public final Number fromString( String _s, Environment _env ) throws ParseException
  {
    try {
      return this.num.valueOf( _s, _env );
    }
    catch (ParseException e) {
      // continue
    }
    catch (NumberFormatException e) {
      // continue
    }
    return Runtime_v2.parseDateAndOrTime( _s, _env, ComputationMode.EXCEL == getComputationMode() );
  }


  public boolean toBoolean( Object _value )
  {
    return valueToBoolean( _value, false );
  }


  public String toString( Object _value ) throws InterpreterException
  {
    if (_value == null) {
      return "";
    }
    else if (_value instanceof String) {
      return (String) _value;
    }
    else if (_value instanceof Number) {
      throw new InterpreterException.IsRuntimeEnvironmentDependent(); // Needs locale.
    }
    else if (_value instanceof Boolean) {
      return ((Boolean) _value) ? "1" : "0";
    }
    return _value.toString();
  }


  public int toInt( Object _value, int _ifNull )
  {
    if (_value == null) return _ifNull;
    return valueToInt( _value, _ifNull );
  }


  public abstract Number toNumeric( Number _value );


  public Object compute( Operator _operator, Object... _args ) throws InterpreterException
  {
    switch (_operator) {

      case CONCAT: {
        StringBuilder result = new StringBuilder();
        for (Object arg : _args) {
          result.append( toString( arg ) );
        }
        return result.toString();
      }

      case EQUAL: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) == 0;
        }
        break;
      }

      case NOTEQUAL: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) != 0;
        }
        break;
      }

      case GREATER: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) > 0;
        }
        break;
      }

      case GREATEROREQUAL: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) >= 0;
        }
        break;
      }

      case LESS: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) < 0;
        }
        break;
      }

      case LESSOREQUAL: {
        switch (_args.length) {
          case 2:
            return compare( _args[ 0 ], _args[ 1 ] ) <= 0;
        }
        break;
      }

    }

    throw new EvalNotPossibleException();
  }

  @SuppressWarnings( "unused" )
  public Object compute( Function _function, Object... _args ) throws InterpreterException
  {
    final int cardinality = _args.length;
    switch (_function) {

      case IF: { // short-circuit eval
        switch (cardinality) {
          case 2:
            return toBoolean( _args[ 0 ] ) ? _args[ 1 ] : false;
          case 3:
            return toBoolean( _args[ 0 ] ) ? _args[ 1 ] : _args[ 2 ];
        }
        break;
      }

      case NOT: {
        switch (cardinality) {
          case 1:
            return !toBoolean( _args[ 0 ] );
        }
        break;
      }

      case INDEX: {
        switch (cardinality) {
          case 2:
            return evalIndex( (ExpressionNodeForArrayReference) _args[ 0 ], _args[ 1 ] );
          case 3:
            return evalIndex( (ExpressionNodeForArrayReference) _args[ 0 ], _args[ 1 ], _args[ 2 ] );
        }
        break;
      }

      case MATCH: {
        switch (cardinality) {
          case 2:
            return toNumeric( match( _args[ 0 ], _args[ 1 ], 1 ) + 1 );
          case 3:
            return toNumeric( match( _args[ 0 ], _args[ 1 ], valueToIntOrOne( _args[ 2 ] ) ) + 1 );
        }
        break;
      }

      case COUNT: {
        return _args.length;
      }

    }

    throw new EvalNotPossibleException();
  }


  private Object evalIndex( ExpressionNodeForArrayReference _range, Object _index )
  {
    int index = valueToIntOrZero( _index );
    return ((ExpressionNodeForConstantValue) _range.argument( index - 1 )).value();
  }


  private Object evalIndex( ExpressionNodeForArrayReference _range, Object _rowIndex, Object _colIndex )
  {
    final ArrayDescriptor desc = _range.arrayDescriptor();
    final int iRow = valueToIntOrOne( _rowIndex ) - 1;
    final int iCol = valueToIntOrOne( _colIndex ) - 1;
    int iValue;
    if (iRow < 0 || iRow >= desc.numberOfRows())
      throw new FormulaException( "#VALUE/REF! because row out of range in INDEX" );
    if (iCol < 0 || iCol >= desc.numberOfColumns())
      throw new FormulaException( "#VALUE/REF! because column out of range in INDEX" );
    if (null != _rowIndex && null != _colIndex) {
      iValue = iRow * desc.numberOfColumns() + iCol;
    }
    else {
      iValue = iRow + iCol;
    }
    return ((ExpressionNodeForConstantValue) _range.argument( iValue )).value();
  }


  @SuppressWarnings( "unchecked" )
  public static int match( Object _lookup, Object _in, int _type )
  {
    if (null == _in) {
      throw new FormulaException( "#VALUE! because range is empty in MATCH" );
    }
    final ExpressionNodeForArrayReference range = (ExpressionNodeForArrayReference) _in;
    if (0 == _type) {
      int iObj = 0;
      for (Object arg : range.arguments()) {
        final Object elt = ((ExpressionNodeForConstantValue) arg).value();
        if (_lookup.equals( elt )) return iObj;
        iObj++;
      }
      throw new NotAvailableException();
    }
    else {
      final Comparable comp = (Comparable) _lookup;
      final int isToRightWhenComparesAs = (_type > 0) ? 1 : -1;
      final List<ExpressionNode> args = range.arguments();
      final int iLast = args.size() - 1;
      int iLeft = 0;
      int iRight = iLast;
      while (iLeft < iRight) {
        final int iMid = iLeft + ((iRight - iLeft) >> 1);
        final Object arg = args.get( iMid );
        final Object elt = ((ExpressionNodeForConstantValue) arg).value();
        final int compRes = comp.compareTo( elt );
        if (compRes == isToRightWhenComparesAs) iLeft = iMid + 1;
        else iRight = iMid;
      }
      if (iLeft <= iLast) {
        final Object arg = args.get( iLeft );
        final Object elt = ((ExpressionNodeForConstantValue) arg).value();
        final int compRes = comp.compareTo( elt );
        if (compRes == 0 || compRes == isToRightWhenComparesAs) return iLeft;
      }
      if (iLeft == 0) throw new NotAvailableException();
      return iLeft - 1;
    }
  }


  protected int valueToInt( Object _value, int _ifNull )
  {
    if (_value instanceof Number) return ((Number) _value).intValue();
    if (_value instanceof String) return Integer.valueOf( (String) _value );
    return _ifNull;
  }

  protected final int valueToIntOrZero( Object _value )
  {
    return valueToInt( _value, 0 );
  }

  protected final int valueToIntOrOne( Object _value )
  {
    return valueToInt( _value, 1 );
  }

  protected boolean valueToBoolean( Object _value, boolean _ifNull )
  {
    if (_value instanceof Boolean) return (Boolean) _value;
    if (_value instanceof Number) return (0 != ((Number) _value).intValue());
    if (_value instanceof String) return Boolean.parseBoolean( (String) _value );
    return _ifNull;
  }


  // Conversions for generated code:

  protected final int to_int( Object _o )
  {
    return valueToIntOrOne( _o );
  }

  protected final String to_String( Object _o ) throws InterpreterException
  {
    return toString( _o );
  }

  protected final Number to_Number( Object _o )
  {
    return (Number) _o;
  }


  protected final Object[] asArrayOfConsts( Object _value )
  {
    if (_value instanceof ExpressionNodeForArrayReference) {
      final ExpressionNodeForArrayReference array = (ExpressionNodeForArrayReference) _value;
      final Object[] r = new Object[ array.arrayDescriptor().numberOfElements() ];
      int i = 0;
      for (ExpressionNode cst : array.arguments()) {
        r[ i++ ] = ((ExpressionNodeForConstantValue) cst).value();
      }
      return r;
    }
    else {
      throw new IllegalArgumentException();
    }

  }


  protected ComputationMode getComputationMode()
  {
    return this.computationMode;
  }

}
TOP

Related Classes of org.formulacompiler.compiler.internal.model.interpreter.InterpretedNumericType_Base

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.