/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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.kie.dmn.feel.lang.ast; import org.antlr.v4.runtime.ParserRuleContext; import org.kie.dmn.feel.lang.EvaluationContext; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; public class ForExpressionNode extends BaseNode { private List<IterationContextNode> iterationContexts; private BaseNode expression; public ForExpressionNode(ParserRuleContext ctx, ListNode iterationContexts, BaseNode expression) { super( ctx ); this.iterationContexts = new ArrayList<>( ); this.expression = expression; for( BaseNode n : iterationContexts.getElements() ) { this.iterationContexts.add( (IterationContextNode) n ); } } public List<IterationContextNode> getIterationContexts() { return iterationContexts; } public void setIterationContexts(List<IterationContextNode> iterationContexts) { this.iterationContexts = iterationContexts; } public BaseNode getExpression() { return expression; } public void setExpression(BaseNode expression) { this.expression = expression; } @Override public Object evaluate(EvaluationContext ctx) { try { ctx.enterFrame(); List results = new ArrayList( ); ForIteration[] ictx = initializeContexts( ctx, iterationContexts); while ( nextIteration( ctx, ictx ) ) { Object result = expression.evaluate( ctx ); results.add( result ); } return results; } finally { ctx.exitFrame(); } } private boolean nextIteration( EvaluationContext ctx, ForIteration[] ictx ) { int i = ictx.length-1; while ( i >= 0 && i < ictx.length ) { if ( ictx[i].hasNextValue() ) { setValueIntoContext( ctx, ictx[i] ); i++; } else { i--; } } return i >= 0; } private void setValueIntoContext(EvaluationContext ctx, ForIteration forIteration) { ctx.setValue( forIteration.getName(), forIteration.getNextValue() ); } private ForIteration[] initializeContexts(EvaluationContext ctx, List<IterationContextNode> iterationContexts) { ForIteration[] ictx = new ForIteration[iterationContexts.size()]; int i = 0; for ( IterationContextNode icn : iterationContexts ) { ictx[i] = createQuantifiedExpressionIterationContext( ctx, icn ); if( i < iterationContexts.size()-1 && ictx[i].hasNextValue() ) { setValueIntoContext( ctx, ictx[i] ); } i++; } return ictx; } private ForIteration createQuantifiedExpressionIterationContext(EvaluationContext ctx, IterationContextNode icn) { String name = icn.evaluateName( ctx ); Object result = icn.evaluate( ctx ); Iterable values = result instanceof Iterable ? (Iterable) result : Collections.singletonList( result ); ForIteration fi = new ForIteration( name, values ); return fi; } private static class ForIteration { private String name; private Iterable values; private Iterator iterator; public ForIteration(String name, Iterable values) { this.name = name; this.values = values; } public boolean hasNextValue() { if( iterator == null ) { iterator = values.iterator(); } boolean hasValue = this.iterator.hasNext(); if( ! hasValue ) { this.iterator = null; } return hasValue; } public Object getNextValue() { return iterator != null ? iterator.next() : null; } public String getName() { return name; } } }