/*
* $Id: ForeachStatement.java,v 1.31 2002/09/16 08:05:06 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.script.statements;
import anvil.core.Any;
import anvil.Location;
import anvil.codec.Code;
import anvil.codec.Source;
import anvil.codec.Target;
import anvil.codec.ConstantPool;
import anvil.parser.Tag;
import anvil.ErrorListener;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import anvil.script.expression.AssignmentNode;
import anvil.script.expression.Expression;
import anvil.script.expression.ExpressionList;
import anvil.script.expression.VariableNode;
import anvil.script.expression.Node;
import anvil.script.parser.TemplateParser;
import anvil.script.Grammar;
import anvil.java.util.BindingEnumeration;
import java.io.IOException;
/**
* class ForeachStatement
*
* @author: Jani Lehtim�ki
*/
public class ForeachStatement extends ScopedStatement implements Labeled
{
private Expression _expression;
private Statement _statement = EMPTY;
private Expression[] _index;
private Expression[] _key;
private Expression[] _value;
private VariableNode _enumvar;
private VariableNode _indexvar;
private String _label ;
private Source _startscope;
private Source _endscope;
public ForeachStatement(Statement parent, Location location)
{
super(parent, location);
}
public ForeachStatement(Statement parent, Location location,
Expression[] index, Expression[] key, Expression[] value,
Expression expression, String label)
{
super(parent, location);
_index = index;
_key = key;
_value = value;
_expression = expression;
_label = label;
}
public int typeOf()
{
return Statement.ST_FOREACH;
}
public String name()
{
return "foreach";
}
public String getLabel()
{
return _label;
}
public void parse(TemplateParser parser, Tag tag)
{
String s;
s = tag.getValue("index");
if (s != null) {
_index = Grammar.parseForeachExpression(s, getLocation(), parser);
}
s = tag.getValue("key");
if (s != null) {
_key = Grammar.parseForeachExpression(s, getLocation(), parser);
}
s = tag.getValue("value");
if (s != null) {
_value = Grammar.parseForeachExpression(s, getLocation(), parser);
}
s = tag.getValue("expr");
if (s == null) {
s = tag.getValue("in");
}
_expression = Grammar.parseExpression(s, getLocation(), parser);
_label = parseLabel(parser, tag);
}
public boolean onTag(TemplateParser parser, int type, Tag tag)
{
switch(type) {
case ST_ENDFOREACH:
parser.pop();
break;
default:
return super.onTag(parser, type, tag);
}
return true;
}
public Statement getChildStatement()
{
return _statement;
}
public void setChildStatement(Statement statement)
{
_statement = statement;
}
public void check(ErrorListener context)
{
if (_index != null) {
int n = _index.length;
for(int i=0; i<n; i++) {
Expression expr = _index[i];
expr.check(context);
if (!expr.isAssignable()) {
context.error(getLocation(), "Index expression #"+(i+1)+" is not assignable");
}
}
}
if (_key != null) {
int n = _key.length;
for(int i=0; i<n; i++) {
Expression expr = _key[i];
expr.check(context);
if (!expr.isAssignable()) {
context.error(getLocation(), "Key expression #"+(i+1)+" is not assignable");
}
}
}
if (_value != null) {
int n = _value.length;
for(int i=0; i<n; i++) {
Expression expr = _value[i];
expr.check(context);
if (!expr.isAssignable()) {
context.error(getLocation(), "Value expression #"+(i+1)+" is not assignable");
}
}
}
_expression.check(context);
_statement.check(context);
FunctionStatement function = getFunctionStatement();
if (function.isGenerator()) {
_enumvar = new VariableNode(function.declare("enum$"+hashCode()));
if (_index != null) {
_indexvar = new VariableNode(function.declare("index$"+hashCode()));
}
}
}
public Jumps eliminate(ErrorListener context)
{
Jumps jumps = _statement.eliminate(context);
jumps.setBlocked(false);
return jumps.shift();
}
public Source getStartOfScope()
{
return _startscope;
}
public Source getEndOfScope()
{
return _endscope;
}
public void compile(ByteCompiler context)
{
Code code = context.getCode();
ConstantPool pool = code.getPool();
FunctionStatement function = getFunctionStatement();
final boolean in_generator = function.isGenerator();
if (_expression.needLineNumbers()) {
context.location(_expression.getLocation());
}
if (in_generator) {
if (_index != null) {
_indexvar.compile(context, new Node()
{
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
code_.getstatic(code_.getPool().addFieldRef(
context.TYPE_ANY, "ZERO", "Lanvil/core/Any;"));
}
});
code.pop();
}
int clazz1 = pool.addClass("java/util/Enumeration");
int clazz2 = pool.addClass("anvil/java/util/BindingEnumeration");
int clazz3 = pool.addClass("anvil/core/AnyBindingEnumeration");
code.anew(clazz3);
code.dup();
_expression.compile(context, Expression.GET);
code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "enumeration", "()Lanvil/java/util/BindingEnumeration;"));
code.invokespecial(pool.addMethodRef(clazz3, "<init>", "(Lanvil/java/util/BindingEnumeration;)V"));
final int tmp = code.addLocal();
code.astore(tmp);
_enumvar.compile(context, new Node()
{
public void compile(ByteCompiler context, int operation)
{
context.getCode().aload(tmp);
}
});
code.endLocal(tmp);
code.pop();
Target start = code.getTarget();
_startscope = code.getSource();
_endscope = code.getSource();
_enumvar.compile(context, Node.GET);
code.invokeinterface(pool.addInterfaceMethodRef(clazz1, "hasMoreElements", "()Z"));
code.if_eq(_endscope);
if (_index != null) {
new AssignmentNode(new ExpressionList(_index,
new Node() {
public void compile(ByteCompiler context, int operation)
{
_indexvar.compile(context, GET);
}
})).compile(context, Node.GET);
code.pop();
_indexvar.compile(context, new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
_indexvar.compile(context, GET);
code_.invokevirtual(code_.getPool().addMethodRef(context.TYPE_ANY,
"increase", "()Lanvil/core/Any;"));
}
});
code.pop();
}
if (_key != null) {
new AssignmentNode(new ExpressionList(_key,
new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
ConstantPool pool_ = code_.getPool();
_enumvar.compile(context, Node.GET);
code_.invokeinterface(pool_.addInterfaceMethodRef("anvil/java/util/BindingEnumeration", "nextKey", "()Ljava/lang/Object;"));
code_.invokestatic(pool_.addMethodRef(context.TYPE_ANY, "create", "(Ljava/lang/Object;)Lanvil/core/Any;"));
}
})).compile(context, Node.GET);
code.pop();
}
if (_value != null) {
new AssignmentNode(new ExpressionList(_value,
new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
ConstantPool pool_ = code_.getPool();
_enumvar.compile(context, Node.GET);
code_.invokeinterface(pool_.addInterfaceMethodRef("java/util/Enumeration", "nextElement", "()Ljava/lang/Object;"));
code_.invokestatic(pool_.addMethodRef(context.TYPE_ANY, "create", "(Ljava/lang/Object;)Lanvil/core/Any;"));
}
})).compile(context, Node.GET);
code.pop();
} else {
_enumvar.compile(context, Node.GET);
code.invokeinterface(pool.addInterfaceMethodRef(clazz1, "nextElement", "()Ljava/lang/Object;"));
code.pop();
}
_statement.compile(context);
code.go_to(_startscope);
_endscope.bind();
_startscope.bind(start);
} else {
final int l_enum = code.addLocal();
final int l_index = (_index != null) ? code.addLocal() : 0;
if (l_index != 0) {
code.iconst(0);
code.istore(l_index);
}
// create enumeration, and wrap it
int clazz1 = pool.addClass("java/util/Enumeration");
int clazz2 = pool.addClass("anvil/java/util/BindingEnumeration");
_expression.compile(context, Expression.GET);
code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "enumeration", "()Lanvil/java/util/BindingEnumeration;"));
code.astore(l_enum);
int sun_hack_1 = 10 + l_enum;
Target start = code.getTarget();
_startscope = code.getSource();
_endscope = code.getSource();
code.aload(l_enum);
int sun_hack_2 = 10 + l_enum;
code.invokeinterface(pool.addInterfaceMethodRef(clazz1, "hasMoreElements", "()Z"));
code.if_eq(_endscope);
if (_index != null) {
new AssignmentNode(new ExpressionList(_index,
new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
code_.iload(l_index);
code_.iinc(l_index, 1);
code_.invokestatic(code_.getPool().addMethodRef(
context.TYPE_ANY, "create", "(I)Lanvil/core/Any;"));
}
})).compile(context, Node.GET);
code.pop();
}
if (_key != null) {
new AssignmentNode(new ExpressionList(_key,
new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
ConstantPool pool_ = code_.getPool();
code_.aload(l_enum);
code_.invokeinterface(pool_.addInterfaceMethodRef("anvil/java/util/BindingEnumeration", "nextKey", "()Ljava/lang/Object;"));
code_.invokestatic(pool_.addMethodRef(context.TYPE_ANY, "create", "(Ljava/lang/Object;)Lanvil/core/Any;"));
}
})).compile(context, Node.GET);
code.pop();
}
if (_value != null) {
new AssignmentNode(new ExpressionList(_value,
new Node() {
public void compile(ByteCompiler context, int operation)
{
Code code_ = context.getCode();
ConstantPool pool_ = code_.getPool();
code_.aload(l_enum);
code_.invokeinterface(pool_.addInterfaceMethodRef("java/util/Enumeration", "nextElement", "()Ljava/lang/Object;"));
code_.invokestatic(pool_.addMethodRef(context.TYPE_ANY, "create", "(Ljava/lang/Object;)Lanvil/core/Any;"));
}
})).compile(context, Node.GET);
code.pop();
} else {
code.aload(l_enum);
code.invokeinterface(pool.addInterfaceMethodRef(clazz1, "nextElement", "()Ljava/lang/Object;"));
code.pop();
}
_statement.compile(context);
code.go_to(_startscope);
_endscope.bind();
_startscope.bind(start);
code.endLocal(l_enum);
if (l_index != 0) {
code.endLocal(l_index);
}
}
}
}