Package com.odiago.flumebase.parser

Source Code of com.odiago.flumebase.parser.BinExpr

/**
* Licensed to Odiago, Inc. under one or more contributor license
* agreements.  See the NOTICE.txt file distributed with this work for
* additional information regarding copyright ownership.  Odiago, Inc.
* licenses this file to you 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 com.odiago.flumebase.parser;

import java.io.IOException;

import java.math.BigDecimal;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.odiago.flumebase.exec.EventWrapper;
import com.odiago.flumebase.exec.SymbolTable;

import com.odiago.flumebase.lang.Type;

/**
* Binary operator expression.
*/
public class BinExpr extends Expr {
  private static final Logger LOG = LoggerFactory.getLogger(BinExpr.class.getName());
  private BinOp mOp;
  private Expr mLeftExpr;
  private Expr mRightExpr;
  private Type mType; // resolved by the type checker.
  private Type mLhsType;
  private Type mRhsType;
  private Type mArgType; // type for the inputs to be coerced to.

  public BinExpr(Expr leftExpr, BinOp op, Expr rightExpr) {
    mLeftExpr = leftExpr;
    mOp = op;
    mRightExpr = rightExpr;
  }

  public BinOp getOp() {
    return mOp;
  }

  public Expr getLeftExpr() {
    return mLeftExpr;
  }

  public void setLeftExpr(Expr left) {
    mLeftExpr = left;
  }

  public Expr getRightExpr() {
    return mRightExpr;
  }

  public void setRightExpr(Expr right) {
    mRightExpr = right;
  }

  @Override
  public void format(StringBuilder sb, int depth) {
    pad(sb, depth);
    sb.append("BinExpr mOp=");
    sb.append(mOp);
    sb.append("\n");
    pad(sb, depth + 1);
    sb.append("left expr:\n");
    mLeftExpr.format(sb, depth + 2);
    pad(sb, depth + 1);
    sb.append("right expr:\n");
    mRightExpr.format(sb, depth + 2);
  }

  @Override
  public String toStringOneLine() {
    StringBuilder sb = new StringBuilder();
    sb.append("(");
    sb.append(mLeftExpr.toStringOneLine());
    sb.append(") ");
    sb.append(symbolForOp(mOp));
    sb.append(" (");
    sb.append(mRightExpr.toStringOneLine());
    sb.append(")");
    return sb.toString();
  }

  private static String symbolForOp(BinOp op) {
    switch (op) {
    case Times:
      return "*";
    case Div:
      return "/";
    case Mod:
      return "%";
    case Add:
      return "+";
    case Subtract:
      return "-";
    case Greater:
      return ">";
    case GreaterEq:
      return ">=";
    case Less:
      return "<";
    case LessEq:
      return "<=";
    case Eq:
      return "=";
    case NotEq:
      return "!=";
    case And:
      return "AND";
    case Or:
      return "OR";
    default:
      throw new RuntimeException("symbolForOp does not understand " + op);
    }
  }

  @Override
  public Type getType(SymbolTable symTab) {
    // Get the types of the lhs and rhs, and then verify that one promotes to the other.
    mLhsType = mLeftExpr.getType(symTab);
    mRhsType = mRightExpr.getType(symTab);
    Type sharedType = null;
    if (mLhsType.promotesTo(mRhsType)) {
      sharedType = mRhsType;
    } else if (mRhsType.promotesTo(mLhsType)) {
      sharedType = mLhsType;
    }

    // Save this for later.
    mArgType = sharedType;

    switch (mOp) {
    case Times:
    case Div:
    case Mod:
    case Add:
    case Subtract:
      // Numeric operators return their input type.
      return sharedType;
    case Greater:
    case GreaterEq:
    case Less:
    case LessEq:
    case Eq:
    case NotEq:
    case And:
    case Or:
      return Type.getPrimitive(Type.TypeName.BOOLEAN);
    default:
      // Couldn't reconcile any type.
      LOG.error("Unknown operator " + mOp + " in getType()");
      return null;
    }
  }

  @Override
  public List<TypedField> getRequiredFields(SymbolTable symTab) {
    List<TypedField> out = new ArrayList<TypedField>();
    out.addAll(mLeftExpr.getRequiredFields(symTab));
    out.addAll(mRightExpr.getRequiredFields(symTab));
    return out;
  }

  @Override
  public Object eval(EventWrapper e) throws IOException {
    Object lhs = mLeftExpr.eval(e);
    Object rhs = mRightExpr.eval(e);

    if (null == lhs || null == rhs) {
      // NULL op X always returns null.
      return null;
    }

    if (!mLhsType.equals(mArgType)) {
      lhs = coerce(lhs, mLhsType, mArgType);
    }

    if (!mRhsType.equals(mArgType)) {
      rhs = coerce(rhs, mRhsType, mArgType);
    }

    switch(mOp) {
    case Times:
      switch (mArgType.getPrimitiveTypeName()) {
      case INT:
        return Integer.valueOf(((Number) lhs).intValue() * ((Number) rhs).intValue());
      case BIGINT:
        return Long.valueOf(((Number) lhs).longValue() * ((Number) rhs).longValue());
      case FLOAT:
        return Float.valueOf(((Number) lhs).floatValue() * ((Number) rhs).floatValue());
      case DOUBLE:
        return Double.valueOf(((Number) lhs).doubleValue() * ((Number) rhs).doubleValue());
      case PRECISE:
        return ((BigDecimal) lhs).multiply((BigDecimal) rhs);
      default:
        LOG.error("Cannot multiply with non-number type " + mArgType);
        return null;
      }
    case Div:
      switch (mArgType.getPrimitiveTypeName()) {
      case INT:
        return Integer.valueOf(((Number) lhs).intValue() / ((Number) rhs).intValue());
      case BIGINT:
        return Long.valueOf(((Number) lhs).longValue() / ((Number) rhs).longValue());
      case FLOAT:
        return Float.valueOf(((Number) lhs).floatValue() / ((Number) rhs).floatValue());
      case DOUBLE:
        return Double.valueOf(((Number) lhs).doubleValue() / ((Number) rhs).doubleValue());
      case PRECISE:
        return ((BigDecimal) lhs).divide((BigDecimal) rhs);
      default:
        LOG.error("Cannot divide with non-number type " + mArgType);
        return null;
      }
    case Mod:
      switch (mArgType.getPrimitiveTypeName()) {
      case INT:
        return Integer.valueOf(((Number) lhs).intValue() % ((Number) rhs).intValue());
      case BIGINT:
        return Long.valueOf(((Number) lhs).longValue() % ((Number) rhs).longValue());
      case FLOAT:
        return Float.valueOf(((Number) lhs).floatValue() % ((Number) rhs).floatValue());
      case DOUBLE:
        return Double.valueOf(((Number) lhs).doubleValue() % ((Number) rhs).doubleValue());
      case PRECISE:
        return ((BigDecimal) lhs).remainder((BigDecimal) rhs);
      default:
        LOG.error("Cannot divide with non-number type " + mArgType);
        return null;
      }
    case Add:
      switch (mArgType.getPrimitiveTypeName()) {
      case INT:
        return Integer.valueOf(((Number) lhs).intValue() + ((Number) rhs).intValue());
      case BIGINT:
        return Long.valueOf(((Number) lhs).longValue() + ((Number) rhs).longValue());
      case FLOAT:
        return Float.valueOf(((Number) lhs).floatValue() + ((Number) rhs).floatValue());
      case DOUBLE:
        return Double.valueOf(((Number) lhs).doubleValue() + ((Number) rhs).doubleValue());
      case PRECISE:
        return ((BigDecimal) lhs).add((BigDecimal) rhs);
      case STRING:
        // String concatenation.
        StringBuilder sb = new StringBuilder();
        sb.append(lhs);
        sb.append(rhs);
        return sb.toString();
      default:
        LOG.error("Cannot divide with non-number type " + mArgType);
        return null;
      }
    case Subtract:
      switch (mArgType.getPrimitiveTypeName()) {
      case INT:
        return Integer.valueOf(((Number) lhs).intValue() - ((Number) rhs).intValue());
      case BIGINT:
        return Long.valueOf(((Number) lhs).longValue() - ((Number) rhs).longValue());
      case FLOAT:
        return Float.valueOf(((Number) lhs).floatValue() - ((Number) rhs).floatValue());
      case DOUBLE:
        return Double.valueOf(((Number) lhs).doubleValue() - ((Number) rhs).doubleValue());
      case PRECISE:
        return ((BigDecimal) lhs).subtract((BigDecimal) rhs);
      default:
        LOG.error("Cannot divide with non-number type " + mArgType);
        return null;
      }
    case Greater:
      return Boolean.valueOf(((Comparable) lhs).compareTo(rhs) > 0);
    case GreaterEq:
      return Boolean.valueOf(((Comparable) lhs).compareTo(rhs) >= 0);
    case Less:
      return Boolean.valueOf(((Comparable) lhs).compareTo(rhs) < 0);
    case LessEq:
      return Boolean.valueOf(((Comparable) lhs).compareTo(rhs) <= 0);
    case Eq:
      return Boolean.valueOf(lhs.equals(rhs));
    case NotEq:
      return Boolean.valueOf(!lhs.equals(rhs));
    case And:
      return Boolean.valueOf(((Boolean) lhs).booleanValue()
          && ((Boolean) rhs).booleanValue());
    case Or:
      return Boolean.valueOf(((Boolean) lhs).booleanValue()
          || ((Boolean) rhs).booleanValue());
    default:
      // Couldn't evaluate this operator.
      throw new RuntimeException("Unknown operator " + mOp + " in eval");
    }
  }

  // Sets the type that the expression returns
  public void setType(Type t) {
    mType = t;
  }

  @Override
  public Type getResolvedType() {
    return mType;
  }

  /**
   * Set the type that the subexpressions should be coerced to.
   */
  private Type getArgType() {
    return mArgType;
  }

  @Override
  public boolean isConstant() {
    return mLeftExpr.isConstant() && mRightExpr.isConstant();
  }
}
TOP

Related Classes of com.odiago.flumebase.parser.BinExpr

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.