/* 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) */