Package org.formulacompiler.compiler.internal.model.rewriting

Source Code of org.formulacompiler.compiler.internal.model.rewriting.AbstractFunctionRewriterForConditionalFold$FilterBuilder

/*
* 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.rewriting;

import static org.formulacompiler.compiler.internal.expressions.ExpressionBuilder.*;

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

import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.Function;
import org.formulacompiler.compiler.Operator;
import org.formulacompiler.compiler.internal.expressions.DataType;
import org.formulacompiler.compiler.internal.expressions.ExpressionNode;
import org.formulacompiler.compiler.internal.expressions.ExpressionNodeForFunction;
import org.formulacompiler.compiler.internal.expressions.ExpressionNodeForLet;
import org.formulacompiler.compiler.internal.expressions.ExpressionNodeForOperator;
import org.formulacompiler.compiler.internal.model.CellModel;
import org.formulacompiler.compiler.internal.model.ComputationModel;
import org.formulacompiler.compiler.internal.model.ExpressionNodeForCellModel;
import org.formulacompiler.compiler.internal.model.interpreter.InterpretedNumericType;
import org.formulacompiler.runtime.New;
import org.formulacompiler.runtime.internal.Environment;


abstract class AbstractFunctionRewriterForConditionalFold extends AbstractExpressionRewriter
{
  private final ComputationModel model;
  private final InterpretedNumericType numericType;
  private final String colPrefix;
  private final String critPrefix;

  public AbstractFunctionRewriterForConditionalFold( ComputationModel _model, InterpretedNumericType _type,
      NameSanitizer _sanitizer )
  {
    super( _sanitizer );
    this.model = _model;
    this.numericType = _type;
    this.colPrefix = "col" + newSanitizingSuffix() + "_";
    this.critPrefix = "crit" + newSanitizingSuffix() + "_";
  }

  public String colPrefix()
  {
    return this.colPrefix;
  }

  public String critPrefix()
  {
    return this.critPrefix;
  }


  protected static final int FREE_FORM = -1;

  protected final class FilterBuilder
  {
    private ExpressionNodeForLet firstLet = null;
    private ExpressionNodeForLet lastLet = null;
    private int nextCritID = 0;


    public ExpressionNode buildFilter( int[] _critCols, List<ExpressionNode> _critData, DataType[] _colTypes,
        List<CellModel> _firstRow ) throws CompilerException
    {
      return join( Function.OR, buildRowFilters( _critCols, _critData.iterator(), _colTypes, _firstRow ) );
    }

    private Collection<ExpressionNode> buildRowFilters( int[] _critCols, Iterator<ExpressionNode> _critIterator,
        DataType[] _colTypes, List<CellModel> _firstRow ) throws CompilerException
    {
      final Collection<ExpressionNode> result = New.collection();
      while (_critIterator.hasNext()) {
        result.add( buildRowFilter( _critCols, _critIterator, _colTypes, _firstRow ) );
      }
      return result;
    }

    private ExpressionNode buildRowFilter( int[] _critCols, Iterator<ExpressionNode> _critIterator,
        DataType[] _colTypes, List<CellModel> _firstRow ) throws CompilerException
    {
      return join( Function.AND, buildColFilters( _critCols, _critIterator, _colTypes, _firstRow ) );
    }

    private Collection<ExpressionNode> buildColFilters( int[] _critCols, Iterator<ExpressionNode> _critIterator,
        DataType[] _colTypes, List<CellModel> _firstRow ) throws CompilerException
    {
      final int len = _critCols.length;
      final Collection<ExpressionNode> result = New.list( len );
      for (int iCrit = 0; iCrit < len; iCrit++) {
        final int iCol = _critCols[ iCrit ];
        final ExpressionNode criterion = _critIterator.next();
        final ExpressionNode colFilter = (iCol == FREE_FORM) ? buildFreeFormFilter( criterion, _firstRow )
            : buildFilterByExample( iCol, criterion, _colTypes[ iCol ] );
        if (null != colFilter) {
          result.add( colFilter );
        }
      }
      return result;
    }

    public ExpressionNode buildFilterByExample( int _tableCol, ExpressionNode _criterion, DataType _type )
        throws CompilerException
    {
      final Object cst = constantValueOf( _criterion );
      if (null == cst) {
        return null;
      }
      else if (cst instanceof String) {
        return buildFilterByExample( _tableCol, (String) cst, _type );
      }
      else {
        final ExpressionNode critExpr = expressionOf( _criterion );
        if (critExpr instanceof ExpressionNodeForOperator) {
          ExpressionNodeForOperator op = (ExpressionNodeForOperator) critExpr;
          switch (op.getOperator()) {
            case CONCAT: {
              final Object cst0 = constantValueOf( op.argument( 0 ) );
              if (cst0 instanceof String) {
                final List<ExpressionNode> args = op.arguments();
                args.remove( 0 );
                return buildFilterByExample( _tableCol, (String) cst0, args, _criterion );
              }
            }
          }
        }
      }
      return buildComparison( Operator.EQUAL, _tableCol, _criterion );
    }

    private ExpressionNode buildFilterByExample( int _tableCol, final String _criterion, DataType _type )
        throws CompilerException
    {
      Operator comparison = Operator.EQUAL;
      int valueStartsAt = 0;
      if (_criterion.startsWith( "=" )) {
        valueStartsAt = 1;
      }
      else if (_criterion.startsWith( "<>" )) {
        comparison = Operator.NOTEQUAL;
        valueStartsAt = 2;
      }
      else if (_criterion.startsWith( "<=" )) {
        comparison = Operator.LESSOREQUAL;
        valueStartsAt = 2;
      }
      else if (_criterion.startsWith( ">=" )) {
        comparison = Operator.GREATEROREQUAL;
        valueStartsAt = 2;
      }
      else if (_criterion.startsWith( "<" )) {
        comparison = Operator.LESS;
        valueStartsAt = 1;
      }
      else if (_criterion.startsWith( ">" )) {
        comparison = Operator.GREATER;
        valueStartsAt = 1;
      }

      final String compareToStr = _criterion.substring( valueStartsAt );
      Object compareTo;
      switch (_type) {
        case NUMERIC:
          try {
            compareTo = numericType().fromString( compareToStr, environment() );
          }
          catch (ParseException e) {
            throw new CompilerException.UnsupportedExpression( e );
          }
          break;
        default:
          compareTo = compareToStr;
      }

      return buildComparison( comparison, _tableCol, cst( compareTo ) );
    }

    private ExpressionNode buildFilterByExample( int _tableCol, String _comparison, List<ExpressionNode> _args,
        ExpressionNode _criterion )
    {
      Operator comparison;
      if (_comparison.equals( "=" )) comparison = Operator.EQUAL;
      else if (_comparison.equals( "<>" )) comparison = Operator.NOTEQUAL;
      else if (_comparison.equals( "<=" )) comparison = Operator.LESSOREQUAL;
      else if (_comparison.equals( ">=" )) comparison = Operator.GREATEROREQUAL;
      else if (_comparison.equals( "<" )) comparison = Operator.LESS;
      else if (_comparison.equals( ">" )) comparison = Operator.GREATER;
      else {
        return op( Operator.EQUAL, var( colPrefix() + _tableCol ), _criterion );
      }
      if (_args.size() == 1) {
        /*
         * We assume that the intention of constructs like
         *
         * =">" & C11
         *
         * was _not_ to cast C11 to string.
         */
        return buildComparison( comparison, _tableCol, _args.iterator().next() );
      }
      else {
        return buildComparison( comparison, _tableCol, new ExpressionNodeForOperator( Operator.CONCAT, _args ) );
      }
    }

    private ExpressionNode buildComparison( Operator _comparison, int _tableCol, ExpressionNode _criterion )
    {
      final String colName = colPrefix() + _tableCol;

      // Unfortunately, constant folding has not been done, because the folder relies on the
      // rewriter having run first.
      if (NOT_CONST != constantValueOf( _criterion )) {
        return op( _comparison, var( colName ), _criterion );
      }
      else {
        final String critName = critPrefix() + this.nextCritID++;

        final ExpressionNodeForLet newLet = new ExpressionNodeForLet( ExpressionNodeForLet.Type.BYNAME, critName,
            _criterion );
        if (this.lastLet == null) {
          this.firstLet = this.lastLet = newLet;
        }
        else {
          this.lastLet.addArgument( newLet );
          this.lastLet = newLet;
        }

        return op( _comparison, var( colName ), var( critName ) );
      }
    }


    private ExpressionNode buildFreeFormFilter( ExpressionNode _criterion, List<CellModel> _firstRow )
        throws CompilerException
    {
      final ExpressionNode critExpr = expressionOf( _criterion );
      return replaceTableCellsByColRefs( critExpr, _firstRow );
    }

    private ExpressionNode replaceTableCellsByColRefs( ExpressionNode _node, List<CellModel> _firstRow )
        throws CompilerException
    {
      if (_node instanceof ExpressionNodeForCellModel) {
        final ExpressionNodeForCellModel cellNode = (ExpressionNodeForCellModel) _node;
        final CellModel cellModel = cellNode.getCellModel();
        final int iCol = _firstRow.indexOf( cellModel );
        if (iCol >= 0) {
          return var( colPrefix() + iCol );
        }
        else {
          return _node;
        }
      }
      else {
        final ExpressionNode clone = _node.cloneWithoutArguments();
        for (ExpressionNode arg : _node.arguments()) {
          clone.addArgument( replaceTableCellsByColRefs( arg, _firstRow ) );
        }
        return clone;
      }
    }


    private ExpressionNode join( Function _joinBy, Collection<ExpressionNode> _nodes )
    {
      if (_nodes.size() == 1) {
        return _nodes.iterator().next();
      }
      else {
        return new ExpressionNodeForFunction( _joinBy, _nodes );
      }
    }


    public ExpressionNode encloseFoldInLets( ExpressionNode _fold )
    {
      if (this.firstLet != null) {
        this.lastLet.addArgument( _fold );
        return this.firstLet;
      }
      else {
        return _fold;
      }
    }


  }


  protected final InterpretedNumericType numericType()
  {
    return this.numericType;
  }

  protected final Environment environment()
  {
    return this.model.getEnvironment();
  }

}
TOP

Related Classes of org.formulacompiler.compiler.internal.model.rewriting.AbstractFunctionRewriterForConditionalFold$FilterBuilder

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.