/******************************************************************************* * Copyright (c) 2011 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SAP AG - initial API and implementation ******************************************************************************/ package com.sap.furcas.prettyprinter.context; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.eclipse.emf.ecore.EObject; import com.sap.furcas.metamodel.FURCAS.TCS.ContextTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement; import com.sap.furcas.metamodel.FURCAS.textblocks.DocumentNode; import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock; import com.sap.furcas.prettyprinter.Formatter.FormatRequest; import com.sap.furcas.prettyprinter.PrettyPrinter; import com.sap.furcas.prettyprinter.TextBlocksFactory; /** * The {@link PrettyPrinter} encapsulates the result of its recursive serialization method calls * in form of {@link PrintResult}s. * * The final result of the pretty printing progress is yield by the combination of all performed * recurisve methods calls. {@link PrintResult}s can therefore be merged * (see {@link ResultContainer#merge(PrintResult)}). * * @author Stephan Erb * */ public abstract class PrintResult { protected final List<DocumentNode> nodes; protected boolean syntacticContribution; protected List<FormatRequest> formatRequests; protected final Collection<EObject> elementsInContext = new ArrayList<EObject>(); public PrintResult(List<DocumentNode> nodes, List<FormatRequest> formatRequests) { this.nodes = nodes; this.formatRequests = formatRequests; } public boolean hasSyntacticContribution() { return syntacticContribution; } public boolean hasSyntacticContribution(boolean contribution) { return syntacticContribution = contribution; } /** * Add formatting (e.g., leading spaced, indentation) applicable for the next * element to be printed, following this result object. */ public void appendFormatRequest(FormatRequest request) { formatRequests.add(request); } /** * Add formatting (e.g., leading spaced, indentation) applicable for the next * element to be printed, following this result object. */ public void appendFormatRequests(Collection<FormatRequest> requests) { formatRequests.addAll(requests); } public void removeFormatRequests(Collection<FormatRequest> requests) { formatRequests.removeAll(requests); } public List<DocumentNode> getNodes() { return nodes; } /** * Used if a serialization method did not produce any result. */ public static class NullResult extends PrintResult { public NullResult() { super(Collections.<DocumentNode>emptyList(), Collections.<FormatRequest>emptyList()); syntacticContribution = false; } @Override public boolean hasSyntacticContribution() { return false; } } /** * Used if a serialization method produced a result. */ public static class LeafResult extends PrintResult { public LeafResult(List<DocumentNode> nodes) { super(nodes, new ArrayList<FormatRequest>()); this.syntacticContribution = true; } public LeafResult(TextBlock node, ResultContainer subResult, List<FormatRequest> formatting) { super(Collections.<DocumentNode>singletonList(node), formatting); this.syntacticContribution = subResult.hasSyntacticContribution(); node.getParentAltChoices().addAll(subResult.getChosenAlternatives()); if (node.getType() instanceof ContextTemplate) { ContextTemplate contextTemplate = (ContextTemplate) node.getType(); if (contextTemplate.isIsContext()) { node.getElementsInContext().addAll(subResult.elementsInContext); } else { // Propagate upwards in order to add the elements to the innermost parent context elementsInContext.addAll(subResult.elementsInContext); } if (contextTemplate.isIsAddToContext()) { // Add the element represented by this block to its inermost parent context elementsInContext.addAll(node.getCorrespondingModelElements()); } } } } /** * Used if several sub-result shall be combined/merged into a single result. */ public static class ResultContainer extends PrintResult { private final List<Integer> chosenAlternatives = new ArrayList<Integer>(); private Collection<FormatRequest> formattingBetweenElements = new ArrayList<FormatRequest>(); private int indentationLevelIncrement = 0; private int alternativeNestingLevelIncrement = 0; private int alternativesNestingLevel = 0; public ResultContainer(List<FormatRequest> formatRequests) { super(new ArrayList<DocumentNode>(), formatRequests); syntacticContribution = false; } public void merge(PrintResult subResult) { if (subResult.hasSyntacticContribution()) { syntacticContribution = true; nodes.addAll(subResult.nodes); formatRequests = subResult.formatRequests; } if (subResult instanceof ResultContainer) { chosenAlternatives.addAll(((ResultContainer) subResult).chosenAlternatives); } elementsInContext.addAll(subResult.elementsInContext); } /** * @param seqElem */ public void mergeChosenAlternative(SequenceElement seqElem, int choice, PrintResult subResult) { alternativesNestingLevel++; chosenAlternatives.add(-alternativesNestingLevel); // marker to indicate nesting chosenAlternatives.add(choice); merge(subResult); chosenAlternatives.add(-alternativesNestingLevel); // marker to indicate nesting alternativesNestingLevel--; } public List<Integer> getChosenAlternatives() { return chosenAlternatives; } public void configureIndentationLevelIncrement(int i) { this.indentationLevelIncrement = i; } public void configureFormattingBetweenBlockElements(Collection<FormatRequest> requests) { this.formattingBetweenElements = requests; } public void configureAlternativeNestingLevel(int i, PrintContext context) { this.alternativeNestingLevelIncrement = i; this.alternativesNestingLevel = context.getAlternativeNestingLevel(); } /** * Create a {@link PrintContext} representing everything that has been pretty printed so far. * This encompasses all information encapusalted in the given context together * with all sub-results that have been printed and merged into this result object. */ public PrintContext asSubContext(final PrintContext context) { return new PrintContext() { @Override public int getPriority() { return context.getPriority(); } @Override public List<FormatRequest> getPendingFormattingRequest() { return formatRequests; } @Override public int getNextOffset() { return TextBlocksFactory.getLengthOf(getNodes(), context.getNextOffset()); } @Override public int getIndenationLevel() { return context.getIndenationLevel() + indentationLevelIncrement; } @Override public EObject getContextElementMatchingTag(String tag) { return context.getContextElementMatchingTag(tag); } @Override public Collection<FormatRequest> getBlockFormattingBetweenElements() { return formattingBetweenElements; } @Override public int getAlternativeNestingLevel() { return context.getAlternativeNestingLevel() + alternativeNestingLevelIncrement; } @Override public SequenceElement getLastSequenceElement() { if (getNodes().isEmpty()) { return context.getLastSequenceElement(); } else { return getNodes().get(getNodes().size()-1).getSequenceElement(); } } }; } } }