org.mvel2.templates.res.CompiledForEachNode Maven / Gradle / Ivy
The newest version!
/**
* MVEL 2.0
* Copyright (C) 2007 The Codehaus
* Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
*
* Licensed 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 org.mvel2.templates.res;
import org.mvel2.CompileException;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.integration.impl.MapVariableResolverFactory;
import org.mvel2.templates.TemplateRuntime;
import org.mvel2.templates.TemplateRuntimeError;
import org.mvel2.templates.util.ArrayIterator;
import org.mvel2.templates.util.CountIterator;
import org.mvel2.templates.util.TemplateOutputStream;
import org.mvel2.util.ParseTools;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class CompiledForEachNode extends Node {
public Node nestedNode;
private Serializable[] ce;
private String[] item;
private char[] sepExpr;
private Serializable cSepExpr;
private ParserContext context;
public CompiledForEachNode(int begin, String name, char[] template, int start, int end, ParserContext context) {
super(begin, name, template, start, end);
this.context = context;
configure();
}
public Node getNestedNode() {
return nestedNode;
}
public void setNestedNode(Node nestedNode) {
this.nestedNode = nestedNode;
}
public boolean demarcate(Node terminatingnode, char[] template) {
nestedNode = next;
next = terminus;
sepExpr = terminatingnode.getContents();
if (sepExpr.length == 0) {
sepExpr = null;
}
else {
cSepExpr = MVEL.compileExpression(sepExpr, context);
}
return false;
}
public Object eval(TemplateRuntime runtime, TemplateOutputStream appender, Object ctx, VariableResolverFactory factory) {
Iterator[] iters = new Iterator[item.length];
Object o;
for (int i = 0; i < iters.length; i++) {
if ((o = MVEL.executeExpression(ce[i], ctx, factory)) instanceof Iterable) {
iters[i] = ((Iterable) o).iterator();
}
else if (o instanceof Object[]) {
iters[i] = new ArrayIterator((Object[]) o);
}
else if (o instanceof Integer) {
iters[i] = new CountIterator((Integer) o);
}
else {
throw new TemplateRuntimeError("cannot iterate object type: " + o.getClass().getName());
}
}
Map locals = new HashMap();
MapVariableResolverFactory localFactory = new MapVariableResolverFactory(locals, factory);
int iterate = iters.length;
while (true) {
for (int i = 0; i < iters.length; i++) {
if (!iters[i].hasNext()) {
iterate--;
locals.put(item[i], "");
}
else {
locals.put(item[i], iters[i].next());
}
}
if (iterate != 0) {
nestedNode.eval(runtime, appender, ctx, localFactory);
if (sepExpr != null) {
for (Iterator it : iters) {
if (it.hasNext()) {
appender.append(String.valueOf(MVEL.executeExpression(cSepExpr, ctx, factory)));
break;
}
}
}
}
else break;
}
return next != null ? next.eval(runtime, appender, ctx, factory) : null;
}
private void configure() {
ArrayList items = new ArrayList();
ArrayList expr = new ArrayList();
int start = cStart;
for (int i = start; i < cEnd; i++) {
switch (contents[i]) {
case '(':
case '[':
case '{':
case '"':
case '\'':
i = ParseTools.balancedCapture(contents, i, contents[i]);
break;
// if (expr.size() < items.size()) {
// start = i;
// i = ParseTools.balancedCapture(contents, i, contents[i]);
// expr.add(ParseTools.createStringTrimmed(contents, start, i - start + 1));
// start = i + 1;
// }
// else {
// throw new CompileException("unexpected character '" + contents[i] + "' in foreach tag", contents,cStart + 1);
// }
// break;
case ':':
items.add(ParseTools.createStringTrimmed(contents, start, i - start));
start = i + 1;
break;
case ',':
if (expr.size() != (items.size() - 1)) {
throw new CompileException("unexpected character ',' in foreach tag", contents, cStart + i);
}
expr.add(ParseTools.createStringTrimmed(contents, start, i - start));
start = i + 1;
break;
}
}
if (start < cEnd) {
if (expr.size() != (items.size() - 1)) {
throw new CompileException("expected character ':' in foreach tag", contents, cEnd);
}
expr.add(ParseTools.createStringTrimmed(contents, start, cEnd - start));
}
item = new String[items.size()];
int i = 0;
for (String s : items) item[i++] = s;
String[] expression;
ce = new Serializable[(expression = new String[expr.size()]).length];
i = 0;
for (String s : expr) {
ce[i] = MVEL.compileExpression(expression[i++] = s, context);
}
}
}