Package org.lilystudio.smarty4j.expression.check

Source Code of org.lilystudio.smarty4j.expression.check.BinaryCheck

package org.lilystudio.smarty4j.expression.check;

import static org.objectweb.asm.Opcodes.*;

import java.util.Map;

import org.lilystudio.smarty4j.expression.IExpression;
import org.lilystudio.smarty4j.expression.number.INumberExpression;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

/**
* 二元弱类型布尔表达式节点, 向JVM语句栈内放入整数值表示两个对象的弱类型逻辑操作结果
*
* @version 0.1.3, 2008/12/12
* @author 欧阳先伟
* @since Smarty 0.1
*/
public abstract class BinaryCheck extends BinaryCheckExpression {

  /** ASM名称 */
  public static final String NAME = BinaryCheck.class.getName().replace('.',
      '/');

  /**
   * 如果变量是能被识别成弱类型浮点数的值则返回<tt>true</tt>
   *
   * @param o
   *          需要识别的变量
   * @return <tt>true</tt>表示变量能被识别成浮点数
   */
  public static boolean isNumeric(Object o) {
    if ((o != null) && !(o instanceof Number) && !(o.equals(""))) {
      String s = o.toString();
      boolean isDouble = false;
      for (int i = s.length() - 1; i >= 0; i--) {
        char c = s.charAt(i);
        if (c == '.') {
          if (isDouble) {
            return false;
          } else {
            isDouble = true;
          }
        } else if (!Character.isDigit(c)) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * 弱类型转换, 将对象转换为浮点数, 其中<tt>null</tt>与空字符串被转换成0.0
   *
   * @param o
   *          源对象
   * @return 源对象对应的浮点数
   */
  public static double o2d(Object o) {
    if (o == null || o.equals("")) {
      return 0.0d;
    } else if (o instanceof Number) {
      return ((Number) o).doubleValue();
    } else {
      return Double.parseDouble(o.toString());
    }
  }

  /**
   * 弱类型转换, 将对象转换为字符串, 其中<tt>null</tt>被转换成空字符串
   *
   * @param o
   *          源对象
   * @return 源对象对应的字符串
   */
  public static String o2s(Object o) {
    return o == null ? "" : o.toString();
  }

  /**
   * 创建二元弱类型布尔表达式节点
   *
   * @param exp1
   *          表达式1
   * @param exp2
   *          表达式2
   */
  public BinaryCheck(IExpression exp1, IExpression exp2) {
    super(exp1, exp2);
  }

  /**
   * 对数值进行二元逻辑操作
   *
   * @param mw
   *          ASM方法操作者
   * @param swap
   *          true表示交换了两个操作数在栈中的顺序
   */
  protected abstract void checkDouble(MethodVisitor mw, boolean swap);

  /**
   * 对字符串进行二元逻辑操作
   *
   * @param mw
   *          ASM方法操作者
   * @param swap
   *          true表示交换了两个操作数在栈中的顺序
   */
  protected abstract void checkString(MethodVisitor mw, boolean swap);

  public void parse(MethodVisitor mw, int local, Map<String, Integer> variableNames) {
    // 在处理过程中, 如果对象的内容不是字符串, 需要先针对变量进行弱类型转换,
    // 只有转换不成功的时候才执行字符串比较
    boolean exp1IsNumber = exp1 instanceof INumberExpression;
    boolean exp2IsNumber = exp2 instanceof INumberExpression;
    if (exp1IsNumber && exp2IsNumber) {
      exp1.parseDouble(mw, local, variableNames);
      exp2.parseDouble(mw, local, variableNames);
      checkDouble(mw, false);
    } else if (exp1IsNumber || exp2IsNumber) {
      // if (弱类型(o) instanceof number) {
      // 数值比较exp1与exp2
      // } else {
      // 字符串比较exp1与exp2
      // }
      Label isString = new Label();
      Label end = new Label();

      IExpression first;
      IExpression second;
      if (exp1IsNumber) {
        first = exp2;
        second = exp1;
      } else {
        first = exp1;
        second = exp2;
      }

      first.parse(mw, local, variableNames);
      mw.visitInsn(DUP);

      mw.visitMethodInsn(INVOKESTATIC, NAME, "isNumeric",
          "(Ljava/lang/Object;)Z");
      mw.visitJumpInsn(IFEQ, isString);

      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2d", "(Ljava/lang/Object;)D");
      second.parseDouble(mw, local, variableNames);
      checkDouble(mw, exp1IsNumber);
      mw.visitJumpInsn(GOTO, end);

      mw.visitLabel(isString);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2s",
          "(Ljava/lang/Object;)Ljava/lang/String;");
      second.parseString(mw, local, variableNames);
      checkString(mw, exp1IsNumber);

      mw.visitLabel(end);
    } else {
      // if (弱类型(exp1) && 弱类型(exp2) instanceof
      // number) {
      // 数值比较exp1与exp2
      // } else {
      // 字符串比较exp1与exp2
      // }
      Label nonString = new Label();
      Label isString = new Label();
      Label end = new Label();

      exp2.parse(mw, local, variableNames);
      exp1.parse(mw, local, variableNames);
      mw.visitVarInsn(ASTORE, local);
      mw.visitVarInsn(ASTORE, local + 1);

      mw.visitVarInsn(ALOAD, local);
      mw.visitTypeInsn(INSTANCEOF, "java/lang/String");
      mw.visitJumpInsn(IFEQ, nonString);
      mw.visitVarInsn(ALOAD, local + 1);
      mw.visitTypeInsn(INSTANCEOF, "java/lang/String");
      mw.visitJumpInsn(IFNE, isString);

      mw.visitLabel(nonString);
      mw.visitVarInsn(ALOAD, local);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "isNumeric",
          "(Ljava/lang/Object;)Z");
      mw.visitJumpInsn(IFEQ, isString);

      mw.visitVarInsn(ALOAD, local + 1);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "isNumeric",
          "(Ljava/lang/Object;)Z");
      mw.visitJumpInsn(IFEQ, isString);

      mw.visitVarInsn(ALOAD, local);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2d", "(Ljava/lang/Object;)D");
      mw.visitVarInsn(ALOAD, local + 1);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2d", "(Ljava/lang/Object;)D");
      checkDouble(mw, false);
      mw.visitJumpInsn(GOTO, end);

      mw.visitLabel(isString);
      mw.visitVarInsn(ALOAD, local);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2s",
          "(Ljava/lang/Object;)Ljava/lang/String;");
      mw.visitVarInsn(ALOAD, local + 1);
      mw.visitMethodInsn(INVOKESTATIC, NAME, "o2s",
          "(Ljava/lang/Object;)Ljava/lang/String;");
      checkString(mw, false);

      mw.visitLabel(end);
    }
  }
}
TOP

Related Classes of org.lilystudio.smarty4j.expression.check.BinaryCheck

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.