org.netxilia.spi.impl.formula.parser.ASTNumericExpression.java Source code

Java tutorial

Introduction

Here is the source code for org.netxilia.spi.impl.formula.parser.ASTNumericExpression.java

Source

/*******************************************************************************
 * 
 * Copyright 2010 Alexandru Craciun, and individual contributors as indicated
 * by the @authors tag. 
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 * 
 * This software 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.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 ******************************************************************************/
/* Generated By:JJTree: Do not edit this line. ASTNumericExpression.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=false,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.netxilia.spi.impl.formula.parser;

import org.joda.time.DateTimeConstants;
import org.joda.time.Duration;
import org.joda.time.LocalDateTime;
import org.joda.time.Period;
import org.joda.time.ReadablePeriod;
import org.netxilia.api.formula.IFormulaContext;
import org.netxilia.api.utils.DateUtils;
import org.netxilia.api.value.DateValue;
import org.netxilia.api.value.ErrorValue;
import org.netxilia.api.value.ErrorValueType;
import org.netxilia.api.value.GenericValueType;
import org.netxilia.api.value.IGenericValue;
import org.netxilia.api.value.NumberValue;

/**
 * An AST node representing a binary numeric expression.
 */
public class ASTNumericExpression extends ASTBinaryExpression {

    public ASTNumericExpression(int id) {
        super(id, "Numeric");
    }

    public ASTNumericExpression(FormulaParser p, int id) {
        super(p, id, "Numeric");
    }

    private ReadablePeriod period(double value) {
        int days = (int) value;
        int millis = (int) (value - days);
        return Period.days(days).plusMillis(millis);
    }

    private IGenericValue dateOperations(IGenericValue gvLeft, IGenericValue gvRight) {

        // D + P, P + D, D - D, D - P
        if (gvLeft.getValueType() == GenericValueType.DATE) {

            if ("+".equals(operator)) {
                // D + P
                LocalDateTime result = DateUtils
                        .toLocalDateTime(gvLeft.getDateValue(), DateValue.ORIGIN.toLocalDateTime())
                        .plus(period(gvRight.getNumberValue().doubleValue()));
                return new DateValue(result);
            }
            if ("-".equals(operator)) {
                if (gvRight.getValueType() == GenericValueType.DATE) {
                    // D - D
                    Double result = (double) (new Duration(gvRight.getDateValue().toDateTime(DateValue.ORIGIN),
                            gvLeft.getDateValue().toDateTime(DateValue.ORIGIN)).getMillis())
                            / DateTimeConstants.MILLIS_PER_DAY;
                    return new NumberValue(result);
                } else {
                    // D - P
                    LocalDateTime result = DateUtils
                            .toLocalDateTime(gvLeft.getDateValue(), DateValue.ORIGIN.toLocalDateTime())
                            .minus(period(gvRight.getNumberValue().doubleValue()));
                    return new DateValue(result);
                }
            }
            // other operations are not allowed - fall through number operations
        } else if (gvRight.getValueType() == GenericValueType.DATE) {
            if ("+".equals(operator)) {
                // P + D
                LocalDateTime result = DateUtils
                        .toLocalDateTime(gvRight.getDateValue(), DateValue.ORIGIN.toLocalDateTime())
                        .plus(period(gvLeft.getNumberValue().doubleValue()));
                return new DateValue(result);
            }
        }
        return null;

    }

    @Override
    public IGenericValue eval(IFormulaContext context) {
        ASTBaseNode nLeft = (ASTBaseNode) jjtGetChild(0);
        ASTBaseNode nRight = (ASTBaseNode) jjtGetChild(1);

        IGenericValue gvLeft = nLeft.eval(context);
        IGenericValue gvRight = nRight.eval(context);

        if (gvLeft.getValueType() == GenericValueType.ERROR) {
            return gvLeft;
        }
        if (gvRight.getValueType() == GenericValueType.ERROR) {
            return gvRight;
        }

        // date operations
        if (gvLeft.getValueType() == GenericValueType.DATE || gvRight.getValueType() == GenericValueType.DATE) {
            IGenericValue result = dateOperations(gvLeft, gvRight);
            if (result != null) {
                return result;
            }
        }

        // number operations
        Double vLeft = gvLeft.getNumberValue();
        Double vRight = gvRight.getNumberValue();

        if ((vLeft == null) || (vRight == null)) {
            return new ErrorValue(ErrorValueType.VALUE);
        }
        double result, left = vLeft.doubleValue(), right = vRight.doubleValue();
        if ("+".equals(operator)) {
            result = left + right;
        } else if ("-".equals(operator)) {
            result = left - right;
        } else if ("*".equals(operator)) {
            result = left * right;
        } else if ("/".equals(operator)) {
            if (Math.abs(right) < NumberValue.APPROXIMATE_ZERO) {
                return new ErrorValue(ErrorValueType.DIV_ZERO);
            }
            result = left / right;
        } else if ("^".equals(operator)) {
            result = Math.pow(left, right);
        } else {
            throw new IllegalStateException("BUG: Unknown operator " + operator);
        }
        return new NumberValue(Double.valueOf(result));
    }
}
/* JavaCC - OriginalChecksum=7b1c18675f52787340e0cdf8aef060cc (do not edit this line) */