LoopModelTransformer.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.functional.core.transformer;
import org.sandbox.functional.core.model.*;
import org.sandbox.functional.core.operation.*;
import org.sandbox.functional.core.renderer.StreamPipelineRenderer;
import org.sandbox.functional.core.terminal.*;
/**
* Transforms a LoopModel into a stream pipeline using a renderer.
*
* <p>This class is the central transformation engine. It iterates through
* the LoopModel's operations and terminals, delegating rendering to the
* provided {@link StreamPipelineRenderer}.</p>
*
* @param <T> the output type (e.g., String for StringRenderer, Expression for ASTRenderer)
*/
public class LoopModelTransformer<T> {
private final StreamPipelineRenderer<T> renderer;
public LoopModelTransformer(StreamPipelineRenderer<T> renderer) {
this.renderer = renderer;
}
/**
* Transforms the given LoopModel into the target representation.
*
* @param model the loop model to transform
* @return the transformed result
*/
public T transform(LoopModel model) {
if (model == null || model.getSource() == null) {
throw new IllegalArgumentException("LoopModel and source must not be null");
}
String varName = model.getElement() != null
? model.getElement().variableName()
: "x";
// Start with source
T pipeline = renderer.renderSource(model.getSource());
// Apply operations
for (Operation op : model.getOperations()) {
pipeline = applyOperation(pipeline, op, varName);
}
// Apply terminal
if (model.getTerminal() != null) {
pipeline = applyTerminal(pipeline, model.getTerminal(), varName);
}
return pipeline;
}
private T applyOperation(T pipeline, Operation op, String varName) {
return switch (op) {
case FilterOp f -> renderer.renderFilter(pipeline, f.expression(), varName);
case MapOp m -> renderer.renderMap(pipeline, m.expression(), varName, m.targetType());
case FlatMapOp fm -> renderer.renderFlatMap(pipeline, fm.expression(), varName);
case PeekOp p -> renderer.renderPeek(pipeline, p.expression(), varName);
case DistinctOp d -> renderer.renderDistinct(pipeline);
case SortOp s -> renderer.renderSorted(pipeline, s.expression());
case LimitOp l -> renderer.renderLimit(pipeline, l.maxSize());
case SkipOp sk -> renderer.renderSkip(pipeline, sk.count());
};
}
private T applyTerminal(T pipeline, TerminalOperation terminal, String varName) {
return switch (terminal) {
case ForEachTerminal fe -> renderer.renderForEach(
pipeline, fe.bodyStatements(), varName, fe.ordered());
case CollectTerminal c -> renderer.renderCollect(pipeline, c, varName);
case ReduceTerminal r -> renderer.renderReduce(pipeline, r, varName);
case CountTerminal ct -> renderer.renderCount(pipeline);
case FindTerminal f -> renderer.renderFind(pipeline, f.findFirst());
case MatchTerminal m -> renderer.renderMatch(pipeline, m, varName);
};
}
/**
* Checks if the model can be transformed.
*/
public boolean canTransform(LoopModel model) {
if (model == null || model.getSource() == null) return false;
return model.isConvertible();
}
}