/**
* Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.parser.prettyprinterv2;
import java.io.IOException;
import java.util.List;
import java.util.Stack;
import org.python.pydev.parser.jython.ISpecialStr;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.For;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.If;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.TryExcept;
import org.python.pydev.parser.jython.ast.TryFinally;
import org.python.pydev.parser.jython.ast.VisitorBase;
import org.python.pydev.parser.jython.ast.While;
import org.python.pydev.parser.jython.ast.With;
import org.python.pydev.parser.jython.ast.commentType;
import org.python.pydev.parser.jython.ast.stmtType;
import org.python.pydev.shared_core.structure.Tuple;
/**
* Utilities for pretty printing.
*/
public class PrettyPrinterUtilsV2 extends VisitorBase {
protected IPrettyPrinterPrefs prefs;
protected PrettyPrinterDocV2 doc;
public PrettyPrinterUtilsV2(IPrettyPrinterPrefs prefs, PrettyPrinterDocV2 doc) {
this.prefs = prefs;
this.doc = doc;
}
private void writeSpecialsBefore(SimpleNode node) throws IOException {
if (node == null) {
return;
}
List<Object> specialsBefore = node.specialsBefore;
if (specialsBefore == null) {
return;
}
writeSpecials(node, specialsBefore);
}
private void writeSpecialsAfter(SimpleNode node) throws IOException {
if (node == null) {
return;
}
List<Object> specialsAfter = node.specialsAfter;
if (specialsAfter == null) {
return;
}
writeSpecials(node, specialsAfter);
}
/**
* Adds the special tokens as tokens in the document.
*/
private void writeSpecials(SimpleNode node, List<Object> specials) {
for (Object c : specials) {
if (c instanceof commentType) {
commentType comment = (commentType) c;
doc.add(comment.beginLine, comment.beginColumn, comment.id, comment);
} else if (c instanceof Name) {
Name name = (Name) c;
doc.add(name.beginLine, name.beginColumn, name.id, name);
} else if (c instanceof ISpecialStr) {
ISpecialStr specialStr = (ISpecialStr) c;
doc.add(specialStr.getBeginLine(), specialStr.getBeginCol(), specialStr.toString(), specialStr);
} else {
throw new RuntimeException("Unexpected special: '" + c + "' Class: " + c.getClass() + ". Node: " + node);
}
}
}
Stack<Integer> ids = new Stack<Integer>();
/**
* Writes the specials before and starts recording
* @throws Exception
*/
protected void beforeNode(SimpleNode node) throws Exception {
this.lastNode = node;
beforeNodeWithoutSettintgLastNode(node);
}
protected void beforeNodeWithoutSettintgLastNode(SimpleNode node) throws IOException {
if (node instanceof stmtType && !isMultiLineStmt((stmtType) node)) {
startStatementPart();
}
writeSpecialsBefore(node);
}
public static boolean isMultiLineStmt(stmtType node) {
return node instanceof ClassDef || node instanceof For || node instanceof FunctionDef || node instanceof If
|| node instanceof TryExcept || node instanceof TryFinally || node instanceof While
|| node instanceof With;
}
protected void afterNode(SimpleNode node) throws IOException {
if (node instanceof stmtType && !isMultiLineStmt((stmtType) node)) {
endStatementPart(node);
}
writeSpecialsAfter(node);
}
protected void startStatementPart() {
ids.push(doc.pushRecordChanges());
}
protected Tuple<ILinePart, ILinePart> endStatementPart(SimpleNode node) {
List<ILinePart> recordChanges = doc.popRecordChanges(ids.pop());
Tuple<ILinePart, ILinePart> lowerAndHigher = doc.getLowerAndHigerFound(recordChanges);
if (lowerAndHigher != null) {
doc.addStartStatementMark(lowerAndHigher.o1, node);
doc.addEndStatementMark(lowerAndHigher.o2, node);
return lowerAndHigher;
}
return null;
}
protected void indent(SimpleNode node, boolean requireNewLine) {
doc.addIndent(node, requireNewLine);
}
protected LinePartIndentMark dedent() {
return doc.addDedent();
}
protected void dedent(int emptyLinesRequiredAfterDedent) {
doc.addDedent(emptyLinesRequiredAfterDedent);
}
protected SimpleNode lastNode;
@Override
protected Object unhandled_node(SimpleNode node) throws Exception {
this.lastNode = node;
return null;
}
@Override
public void traverse(SimpleNode node) throws Exception {
beforeNode(node);
node.traverse(this);
afterNode(node);
}
}