Package org.lilystudio.smarty4j.statement.function

Source Code of org.lilystudio.smarty4j.statement.function.$section

package org.lilystudio.smarty4j.statement.function;

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

import java.util.List;
import java.util.Map;

import org.lilystudio.smarty4j.Context;
import org.lilystudio.smarty4j.ParseException;
import org.lilystudio.smarty4j.Template;
import org.lilystudio.smarty4j.expression.IExpression;
import org.lilystudio.smarty4j.expression.check.TrueCheck;
import org.lilystudio.smarty4j.expression.number.ConstInteger;
import org.lilystudio.smarty4j.statement.Block;
import org.lilystudio.smarty4j.statement.BlockStatement;
import org.lilystudio.smarty4j.statement.IBlockFunction;
import org.lilystudio.smarty4j.statement.ILoop;
import org.lilystudio.smarty4j.statement.IStatement;
import org.lilystudio.smarty4j.statement.ParameterCharacter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

/**
* 高级循环函数。
*
* <pre>
* name--循环内的变量名称
* loop--循环体
* start--开始时的坐标
* step--步长
* max--循环最多执行的次数
* show--是否显示
* </pre>
*
* @version 1.0.0, 2010/10/01
* @author 欧阳先伟
* @since Smarty 1.0
*/
public class $section extends Block implements ILoop {

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

  /** 参数定义 */
  private static ParameterCharacter[] definitions = {
      new ParameterCharacter(ParameterCharacter.OBJECT, "loop"),
      new ParameterCharacter(ParameterCharacter.STRING, "name"),
      new ParameterCharacter(ParameterCharacter.INTOBJECT, new ConstInteger(0),
          "start"),
      new ParameterCharacter(ParameterCharacter.INTOBJECT, new ConstInteger(1),
          "step"),
      new ParameterCharacter(ParameterCharacter.INTOBJECT, new ConstInteger(0),
          "max"),
      new ParameterCharacter(ParameterCharacter.BOOLEAN, new TrueCheck(),
          "show") };

  /**
   * 获取一个循环体源对象包含的对象数组, 如果源对象是Map, 将取回关键字对应的数组,
   * 如果无法将源对象转换成等价的对象数组, 源对象将直接被返回
   *
   * @param o
   *          需要循环的源对象
   * @param start
   *          数组开始位置
   * @param step
   *          循环步长
   * @param max
   *          最多的循环次数, 如果为0表示要循环所有的值
   * @return 源对象数组
   */
  public static Object[] getLooper(Object o, int start, int step, int max) {
    Object[] list;
    if (o instanceof List) {
      list = ((List<?>) o).toArray();
    } else if (o instanceof Object[]) {
      list = (Object[]) o;
    } else if (o instanceof Map) {
      list = ((Map<?, ?>) o).values().toArray();
    } else {
      list = new Object[] { o };
    }
    int size = list.length - 1;
    if (start > size) {
      start = size;
    }
    size = step > 0 ? (size - start) / step + 1 : start / -step + 1;
    if (max > 0 && max < size) {
      size = max;
    }
    Object[] result = new Object[size];
    for (int i = 0; i < size; i++) {
      result[i] = list[start];
      start += step;
    }
    return result;
  }

  /** 循环开始标签 */
  private Label startLabel = new Label();

  /** 循环结束标签 */
  private Label endLabel = new Label();

  /** 循环体为空时对应的区块 */
  private IBlockFunction elseBlock;

  public Label getStartLabel() {
    return startLabel;
  }

  public Label getEndLabel() {
    return endLabel;
  }

  public void restore(MethodVisitor mw, Map<String, Integer> variableNames) {
    mw.visitInsn(POP2);
    if (variableNames == null) {
      mw.visitMethodInsn(INVOKEVIRTUAL, Context.NAME, "set",
          "(Ljava/lang/String;Ljava/lang/Object;)V");
    }
  }

  @Override
  public void addStatement(IStatement statement) throws ParseException {
    if (statement instanceof $sectionelse) {
      if (elseBlock != null) {
        throw new ParseException("不能重复定义sectionelse");
      } else {
        elseBlock = new BlockStatement();
        elseBlock.setParent(this.getParent());
      }
    } else if (elseBlock != null) {
      elseBlock.addStatement(statement);
    } else {
      super.addStatement(statement);
    }
  }

  public ParameterCharacter[] getDefinitions() {
    return definitions;
  }

  @Override
  public void scan(Template template) {
    super.scan(template);
    if (elseBlock != null) {
      elseBlock.scan(template);
    }
  }

  @Override
  public void parse(MethodVisitor mw, int local,
      Map<String, Integer> variableNames) {
    Integer oldNameValue = null;

    IExpression name = getParameter(1);

    Label isnull = new Label();
    Label loopstart = new Label();
    Label end = new Label();

    getParameter(5).parse(mw, local, variableNames);
    mw.visitJumpInsn(IFEQ, end);

    getParameter(0).parseObject(mw, local, variableNames);
    mw.visitVarInsn(ASTORE, local);
    mw.visitVarInsn(ALOAD, local);
    mw.visitJumpInsn(IFNULL, isnull);

    if (variableNames != null) {
      oldNameValue = variableNames.get(name.toString());
      variableNames.put(name.toString(), Integer.valueOf(local + 1));
    } else {
      // 保存原始的循环变量名值
      mw.visitVarInsn(ALOAD, CONTEXT);
      name.parse(mw, local + 1, variableNames);
      mw.visitInsn(DUP2);
      mw.visitMethodInsn(INVOKEVIRTUAL, Context.NAME, "get",
          "(Ljava/lang/String;)Ljava/lang/Object;");
    }

    // 生成用于循环的数组
    mw.visitVarInsn(ALOAD, local);
    getParameter(2).parse(mw, local + 1, variableNames);
    getParameter(3).parse(mw, local + 1, variableNames);
    getParameter(4).parse(mw, local + 1, variableNames);
    mw.visitMethodInsn(INVOKESTATIC, NAME, "getLooper",
        "(Ljava/lang/Object;III)[Ljava/lang/Object;");

    mw.visitInsn(DUP);
    mw.visitInsn(ARRAYLENGTH);
    mw.visitVarInsn(ISTORE, local);
    mw.visitInsn(ICONST_0);

    mw.visitLabel(loopstart);
    mw.visitInsn(DUP);
    mw.visitVarInsn(ILOAD, local);
    mw.visitJumpInsn(IF_ICMPEQ, endLabel);

    mw.visitInsn(DUP2);
    mw.visitInsn(AALOAD);
    if (variableNames != null) {
      mw.visitVarInsn(ASTORE, local + 1);
    } else {
      mw.visitVarInsn(ALOAD, CONTEXT);
      mw.visitInsn(SWAP);
      name.parse(mw, local + 2, variableNames);
      mw.visitInsn(SWAP);
      mw.visitMethodInsn(INVOKEVIRTUAL, Context.NAME, "set",
          "(Ljava/lang/String;Ljava/lang/Object;)V");
    }
    super.parse(mw, local + 2, variableNames);
    mw.visitLabel(startLabel);
    mw.visitInsn(ICONST_1);
    mw.visitInsn(IADD);
    mw.visitJumpInsn(GOTO, loopstart);

    // 循环结束, 恢复恢复过程中被设置的属性的原始值
    mw.visitLabel(endLabel);
    restore(mw, variableNames);
    mw.visitJumpInsn(GOTO, end);

    // 循环源集合为空时的处理
    mw.visitLabel(isnull);
    if (elseBlock != null) {
      elseBlock.parse(mw, local, variableNames);
    }

    mw.visitLabel(end);

    if (variableNames != null) {
      variableNames.put(name.toString(), oldNameValue);
    }
  }
}
TOP

Related Classes of org.lilystudio.smarty4j.statement.function.$section

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.