Package org.openntf.formula.ast

Source Code of org.openntf.formula.ast.ASTAtSort

/* Generated By:JJTree: Do not edit this line. ASTAtSort.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=false,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
/*
* © Copyright FOCONIS AG, 2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
package org.openntf.formula.ast;

import java.util.Set;

import org.openntf.formula.DateTime;
import org.openntf.formula.EvaluateException;
import org.openntf.formula.FormulaContext;
import org.openntf.formula.FormulaReturnException;
import org.openntf.formula.ValueHolder;
import org.openntf.formula.ValueHolder.DataType;
import org.openntf.formula.annotation.DiffersFromLotus;
import org.openntf.formula.parse.AtFormulaParserImpl;

/**
* Implements the {@literal @}Sort commad
*
* TODO RPr: Implement Quicksort!
*
* @author Manfred Steinsiek, Foconis AG
*
*/
public class ASTAtSort extends SimpleNode {

  public ASTAtSort(final AtFormulaParserImpl p, final int id) {
    super(p, id);
  }

  /**
   * regarding to errorhandling, sort is a bit complex as it has more parameters and a lot of code. That's why a try/catch is surrounded
   * that wraps every exception in a ValueHolder
   */
  @Override
  @DiffersFromLotus({ "Options [ACCENT(IN)SENSITIVE] and [PITCH(IN)SENSITIVE] aren't yet supported",
      "Standard string compare is done via String.compareTo" })
  public ValueHolder evaluate(final FormulaContext ctx) throws FormulaReturnException {
    try {
      boolean sortAscending = true;
      boolean sortCaseSensitive = true;
      boolean sortCustom = false;
      if (children.length >= 2) {
        ValueHolder options = children[1].evaluate(ctx);
        if (options.dataType == DataType.ERROR)
          return options;

        for (int i = 0; i < options.size; i++) {
          String opt = options.getString(i);
          if ("[ASCENDING]".equalsIgnoreCase(opt))
            sortAscending = true;
          else if ("[DESCENDING]".equalsIgnoreCase(opt))
            sortAscending = false;
          else if ("[CASESENSITIVE]".equalsIgnoreCase(opt))
            sortCaseSensitive = true;
          else if ("[CASEINSENSITIVE]".equalsIgnoreCase(opt))
            sortCaseSensitive = false;
          else if ("[CUSTOMSORT]".equalsIgnoreCase(opt))
            sortCustom = true;
          else if (!"[ACCENTSENSITIVE]".equalsIgnoreCase(opt) && !"[ACCENTINSENSITIVE]".equalsIgnoreCase(opt)
              && !"[PITCHSENSITIVE]".equalsIgnoreCase(opt) && !"[PITCHINSENSITIVE]".equalsIgnoreCase(opt))
            throw new IllegalArgumentException("Illegal Option: " + opt);
        }
      }
      Node customSort = null;
      if (sortCustom) {
        if (children.length < 3)
          throw new IllegalArgumentException("Third argument required since option [CUSTOMSORT] present");
        customSort = children[2];
      }
      ValueHolder toSort = children[0].evaluate(ctx);
      if (toSort.dataType == DataType.ERROR)
        return toSort;

      // we must duplicate our valueholder, since it can be Immutable
      ValueHolder ret = toSort.newInstance(toSort.size);
      ret.addAll(toSort);
      doSort(ctx, ret, sortAscending, sortCaseSensitive, customSort);
      return ret;
    } catch (RuntimeException ex) {
      return ValueHolder.valueOf(new EvaluateException(codeLine, codeColumn, ex));
    }
  }

  /**
   * This does the whole (bubble)sort stuff.
   */
  private void doSort(final FormulaContext ctx, final ValueHolder what, final boolean sortAscending, final boolean sortCaseSensitive,
      final Node customSort) throws FormulaReturnException {
    for (int i = 0; i < what.size; i++) {
      for (int j = i; j < what.size; j++) {
        int cmp;
        if (what.dataType == DataType.STRING)
          cmp = doSortString(ctx, what.getString(i), what.getString(j), sortCaseSensitive, customSort);
        else if (what.dataType.numeric)
          cmp = doSortNumber(ctx, what.getDouble(i), what.getDouble(j), customSort);
        else if (what.dataType == DataType.DATETIME)
          cmp = doSortDateTime(ctx, what.getDateTime(i), what.getDateTime(j), customSort);
        else
          throw new IllegalArgumentException("Can't sort Object of this type: " + what.dataType);
        if (!sortAscending)
          cmp = -cmp;
        if (cmp > 0)
          what.swap(i, j);
      }
    }
  }

  /**
   * compares two given strings.
   */
  private int doSortString(final FormulaContext ctx, final String s1, final String s2, final boolean sortCaseSensitive,
      final Node customSort) throws FormulaReturnException {
    if (customSort == null)
      return (sortCaseSensitive ? s1.compareTo(s2) : s1.compareToIgnoreCase(s2));

    ValueHolder oldA = ctx.setVarLC("$a", ValueHolder.valueOf(s1));
    ValueHolder oldB = ctx.setVarLC("$b", ValueHolder.valueOf(s2));
    try {
      ValueHolder vh = customSort.evaluate(ctx);
      return (vh.isTrue(ctx)) ? 1 : -1;
    } finally {
      ctx.setVarLC("$a", oldA);
      ctx.setVarLC("$b", oldB);
    }

  }

  /**
   * compares two given doubles.
   */
  private int doSortNumber(final FormulaContext ctx, final double n1, final double n2, final Node customSort)
      throws FormulaReturnException {
    if (customSort == null)
      return Double.compare(n1, n2);

    ValueHolder oldA = ctx.setVarLC("$a", ValueHolder.valueOf(n1));
    ValueHolder oldB = ctx.setVarLC("$b", ValueHolder.valueOf(n2));
    try {
      ValueHolder vh = customSort.evaluate(ctx);
      return (vh.isTrue(ctx)) ? 1 : -1;
    } finally {
      ctx.setVarLC("$a", oldA);
      ctx.setVarLC("$b", oldB);
    }
  }

  /**
   * Compares two given DateTimes
   */
  private int doSortDateTime(final FormulaContext ctx, final DateTime d1, final DateTime d2, final Node customSort)
      throws FormulaReturnException {
    if (customSort == null)
      return d1.compare(d1, d2);
    ValueHolder oldA = ctx.setVarLC("$a", ValueHolder.valueOf(d1));
    ValueHolder oldB = ctx.setVarLC("$b", ValueHolder.valueOf(d2));
    try {
      ValueHolder vh = customSort.evaluate(ctx);
      return (vh.isTrue(ctx)) ? 1 : -1;
    } finally {
      ctx.setVarLC("$a", oldA);
      ctx.setVarLC("$b", oldB);
    }
  }

  /*
   * (non-Javadoc)
   * @see org.openntf.formula.ast.SimpleNode#analyzeThis(java.util.Set, java.util.Set, java.util.Set, java.util.Set)
   */
  @Override
  protected void analyzeThis(final Set<String> readFields, final Set<String> modifiedFields, final Set<String> variables,
      final Set<String> functions) {
    functions.add("@sort");
  }
}
/* JavaCC - OriginalChecksum=3e128312ed1a8ea1e9f98a467e9c3222 (do not edit this line) */ 
TOP

Related Classes of org.openntf.formula.ast.ASTAtSort

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.