/* Copyright (C) 2004 - 2008 Versant Inc. http://www.db4o.com
This file is part of the sharpen open source java to c# translator.
sharpen is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.
sharpen is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
package sharpen.core.csharp;
import sharpen.core.csharp.ast.*;
import sharpen.core.io.IndentedWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CSharpPrinter extends CSVisitor {
protected IndentedWriter _writer;
protected CSTypeDeclaration _currentType;
private int _lastPrintedCommentIndex;
private List<CSLineComment> _comments;
public CSharpPrinter() {
}
public void setWriter(Writer writer) {
_writer = new IndentedWriter(writer);
}
public void print(CSCompilationUnit node) {
_lastPrintedCommentIndex = 0;
_comments = node.comments();
try {
node.accept(this);
} finally {
_currentType = null;
_comments = null;
}
}
private List<CSUsing> printableUsingList(Iterable<CSUsing> usings) {
List<CSUsing> list = new ArrayList<CSUsing>();
for (CSUsing using : usings) {
list.add(using);
}
Collections.sort(list, new Comparator<CSUsing>() {
public int compare(CSUsing a, CSUsing b) {
boolean ia = a.namespace().startsWith("System");
boolean ib = b.namespace().startsWith("System");
if (ia && ib)
return a.namespace().compareTo(b.namespace());
else if (ia)
return -1;
else if (ib)
return 1;
else
return a.namespace().compareTo(b.namespace());
}
});
return list;
}
static final Pattern META_VARIABLE_PATTERN = Pattern.compile("\\$(\\w+)");
@Override
public void visit(CSMacroExpression node) {
node.macro().accept(this);
}
@Override
public void visit(CSMacroTypeReference node) {
node.macro().accept(this);
}
@Override
public void visit(CSMacro node) {
final String template = node.template();
final Matcher matcher = META_VARIABLE_PATTERN.matcher(template);
int last = 0;
while (matcher.find()) {
write(template.substring(last, matcher.start()));
Object value = node.resolveVariable(matcher.group(1));
// value is either a single node or a list of nodes
if (value instanceof CSNode) {
((CSNode) value).accept(this);
} else {
writeCommaSeparatedList((Iterable<CSNode>) value);
}
last = matcher.end();
}
write(template.substring(last));
}
@Override
public void visit(CSCompilationUnit node) {
beginEnclosingIfDefs(node);
List<CSUsing> usings = printableUsingList(node.usings());
for (CSUsing using : usings) {
using.accept(this);
}
if (usings.size() > 0)
_writer.writeLine();
if (null != node.namespace()) {
writeLine("namespace " + node.namespace());
enterBody();
}
writeLineSeparatedList(node.types());
if (null != node.namespace()) {
leaveBody();
}
endEnclosingIfDefs(node);
}
@Override
public void visit(CSRemovedExpression node) {
throw new IllegalStateException("Unexpected removal of expression: " + node.toString());
}
@Override
public void visit(CSUsing node) {
writeLine("using " + node.namespace() + ";");
}
@Override
public void visit(CSClass node) {
writeType(node);
}
@Override
public void visit(CSEnum node) {
writeMemberHeader(node);
write("enum " + node.name());
if (node.baseType() != null) {
write(" : ");
node.baseType().accept(this);
}
writeLine();
enterBody();
writeSeparatedList(node.values(), new Closure() {
public void execute() {
writeLine(",");
}
});
writeLine();
leaveBody();
}
@Override
public void visit(CSEnumValue node) {
printPrecedingComments(node);
writeDoc(node);
writeIndented(node.name());
if (node.initializer() != null) {
write(" = ");
node.initializer().accept(this);
}
}
@Override
public void visit(CSStruct node) {
CSStructLayout layout = node.getStructLayout();
if (layout != null) {
writeStructLayout(layout);
}
writeType(node);
}
private void writeStructLayout(CSStructLayout layout) {
writeIndented("[StructLayout(");
CSStructLayout.LayoutKind kind = layout.getLayoutKind();
if (kind != null) {
write("LayoutKind.");
switch (kind) {
case Sequential:
write("Sequential");
break;
case Explicit:
write("Explicit");
break;
default:
write("Auto");
break;
}
}
writeLine(")]");
}
@Override
public void visit(CSInterface node) {
writeType(node);
}
@Override
public void visit(CSTypeParameter node) {
write(node.name());
}
@Override
public void visit(final CSArrayTypeReference node) {
node.elementType().accept(this);
for (int i = 0; i < node.dimensions(); ++i) {
write("[]");
}
}
@Override
public void visit(CSTypeReference node) {
write(node.typeName());
writeTypeArguments(node);
}
@Override
public void visit(CSNestedTypeReference node) {
node.getParent().accept(this);
write(".");
node.getChild().accept(this);
}
@Override
public void visit(CSNullableTypeReference node) {
node.getElementType().accept(this);
write("?");
}
@Override
public void visit(CSByRefTypeReference node) {
if (node.isOut())
write("out ");
else
write("ref ");
node.getElementType().accept(this);
}
private void writeTypeArguments(CSTypeArgumentProvider node) {
final List<CSTypeReferenceExpression> typeArgs = node.typeArguments();
if (!typeArgs.isEmpty()) {
writeGenericParameters(typeArgs);
}
}
@Override
public void visit(CSDelegate node) {
writeMemberHeader(node);
write("delegate void ");
write(node.name());
writeParameterList(node.parameters());
writeLine(";");
}
private void writeTypeHeader(CSTypeDeclaration node) {
writeMemberHeader(node);
if (node.isInterface()) {
if (node.partial())
_writer.write("partial ");
write("interface " + node.name());
} else if (node instanceof CSClass) {
CSClass classNode = (CSClass) node;
write(classModifier(classNode.modifier()));
if (node.partial())
_writer.write("partial ");
write("class " + node.name());
} else {
write("struct " + node.name());
}
writeTypeParameters(node);
writeBaseTypes(node);
writeTypeParameterConstraints(node.typeParameters());
}
private void writeMemberHeader(CSTypeDeclaration node) {
writeAttributes(node);
writeVisibility(node);
}
private void writeTypeParameters(CSTypeParameterProvider node) {
final List<CSTypeParameter> parameters = node.typeParameters();
if (parameters.isEmpty())
return;
writeGenericParameters(parameters);
}
private void writeTypeParameterConstraints(List<CSTypeParameter> parameters) {
if (parameters.isEmpty())
return;
for (CSTypeParameter tp : parameters) {
if (tp.superClass() != null) {
write(" where ");
write(tp.name() + ":");
tp.superClass().accept(this);
}
}
}
private <T extends CSNode> void writeGenericParameters(Iterable<T> nodes) {
write("<");
writeCommaSeparatedList(nodes);
write(">");
}
private void writeType(CSTypeDeclaration node) {
writeDoc(node);
beginEnclosingIfDefs(node);
writeTypeHeader(node);
writeTypeBody(node);
endEnclosingIfDefs(node);
}
private void writeBaseTypes(CSTypeDeclaration node) {
List<CSTypeReferenceExpression> baseTypes = node.baseTypes();
if (baseTypes.isEmpty())
return;
write(" : ");
writeCommaSeparatedList(baseTypes);
}
private void writeTypeBody(CSTypeDeclaration node) {
writeLine();
enterBody();
CSTypeDeclaration saved = _currentType;
_currentType = node;
writeLineSeparatedList(node.members());
printPrecedingComments(node.startPosition() + node.sourceLength());
_currentType = saved;
leaveBody();
}
private void writeVisibility(CSMember member) {
writeIndentation();
if (member.isNewModifier())
write("new ");
if (isExplicitMember(member))
return;
CSVisibility visibility = member.visibility();
write(visibility.toString().toLowerCase());
write(" ");
}
private boolean isExplicitMember(CSMember member) {
return member.name().indexOf('.') != -1;
}
private void writeParameterAttributes(CSParameterDeclaration node) {
if (node.attributes() == null)
return;
for (CSAttribute attr : node.attributes()) {
write("[");
write(attr.name());
if (!attr.arguments().isEmpty()) {
writeParameterList(attr.arguments());
}
write("] ");
}
}
@Override
public void visit(CSVariableDeclaration node) {
if (node instanceof CSParameterDeclaration)
writeParameterAttributes((CSParameterDeclaration) node);
node.type().accept(this);
if (null != node.name()) {
write(" ");
write(node.name());
}
if (null != node.initializer()) {
write(" = ");
node.initializer().accept(this);
}
}
@Override
public void visit(CSConstructor node) {
writeDoc(node);
writeAttributes(node);
if (node.isStatic()) {
writeIndented("static ");
} else {
writeVisibility(node);
}
write(_currentType.name());
writeParameterList(node);
if (null != node.chainedConstructorInvocation()) {
write(" : ");
writeMethodInvocation(node.chainedConstructorInvocation());
}
writeLine();
node.body().accept(this);
}
@Override
public void visit(CSDestructor node) {
writeIndented("~");
write(_currentType.name());
writeLine("()");
node.body().accept(this);
}
@Override
public void visit(CSMethod node) {
printPrecedingComments(node);
beginEnclosingIfDefs(node);
writeDoc(node);
writeAttributes(node);
if (node.dllImport() != null)
writeDllImport(node.dllImport());
writeMethodHeader(node, node.modifier());
node.returnType().accept(this);
write(" ");
writeMethodName(node);
writeTypeParameters(node);
writeParameterList(node);
if (node.modifier() != CSMethodModifier.Override)
writeTypeParameterConstraints(node.typeParameters());
if (node.isAbstract() || (node.dllImport() != null)) {
writeLine(";");
} else {
writeMethodBody(node);
}
endEnclosingIfDefs(node);
}
private void writeDllImport(CSDllImport dllImport) {
writeIndented("[DllImport(");
write('"' + dllImport.getDllName() + '"');
CSDllImport.CallingConvention cconv = dllImport.getCallingConvention();
if (cconv != null) {
write(", CallingConvention = CallingConvention.");
switch (cconv) {
case CDecl:
write("Cdecl");
break;
case StdCall:
write("StdCall");
break;
case ThisCall:
write("ThisCall");
break;
default:
write("Winapi");
break;
}
}
CSDllImport.CharSet charSet = dllImport.getCharSet();
if (charSet != null) {
write(", CharSet = CharSet.");
switch (charSet) {
case Ansi:
write("Ansi");
break;
case Unicode:
write("Unicode");
break;
default:
write("Auto");
break;
}
}
writeLine(")]");
}
private void endEnclosingIfDefs(CSNode node) {
for (String expression : node.enclosingIfDefs()) {
writeIndented("#endif // ");
writeLine(expression);
}
}
private void beginEnclosingIfDefs(CSNode node) {
for (String expression : node.enclosingIfDefs()) {
writeIndented("#if ");
writeLine(expression);
}
}
private void writeMethodHeader(CSMember member, CSMethodModifier modifiers) {
if (!_currentType.isInterface()) {
writeVisibility(member);
write(methodModifier(modifiers));
} else {
writeIndentation();
}
}
protected void writeMethodBody(CSMethod node) {
writeLine();
node.body().accept(this);
}
protected void writeMethodName(CSMethod node) {
write(node.name());
}
@Override
public void visit(CSBlock node) {
enterBody();
visitList(node.statements());
leaveBody();
}
@Override
public void visit(CSDeclarationStatement node) {
printPrecedingComments(node);
writeIndentation();
node.declaration().accept(this);
writeLine(";");
}
@Override
public void visit(CSDeclarationExpression node) {
node.declaration().accept(this);
}
private void writeDeclaration(CSTypeReferenceExpression type, String name, CSExpression initializer) {
type.accept(this);
write(" ");
write(name);
if (null != initializer) {
write(" = ");
initializer.accept(this);
}
writeLine(";");
}
@Override
public void visit(CSLineComment node) {
writeIndentedLine(node.text());
}
@Override
public void visit(CSReturnStatement node) {
printPrecedingComments(node);
if (null == node.expression()) {
writeIndentedLine("return;");
} else {
writeIndented("return ");
node.expression().accept(this);
writeLine(";");
}
}
private void printPrecedingComments(CSNode node) {
if ((node instanceof CSMember) && ((CSMember) node).noDocs())
return;
printPrecedingComments(node.startPosition());
}
private void printPrecedingComments(int startPosition) {
if ((_currentType != null) && _currentType.noDocs())
return;
if (startPosition <= 0)
return;
if (_lastPrintedCommentIndex >= _comments.size())
return;
_lastPrintedCommentIndex = printCommentsBetween(_lastPrintedCommentIndex, startPosition);
}
private int printCommentsBetween(int lastIndex, int endStartPosition) {
int endIndex = commentIndexAfter(lastIndex, endStartPosition);
if (endIndex == -1) {
endIndex = _comments.size();
}
if ((_currentType != null) && _currentType.noDocs())
return endIndex;
visitList(_comments.subList(lastIndex, endIndex));
return endIndex;
}
private int commentIndexAfter(int startIndex, int endStartPosition) {
for (int i = startIndex; i < _comments.size(); ++i) {
if (_comments.get(i).startPosition() > endStartPosition) {
return i;
}
}
return -1;
}
@Override
public void visit(CSIfStatement node) {
printPrecedingComments(node);
writeIndented("if (");
node.expression().accept(this);
writeLine(")");
node.trueBlock().accept(this);
if (!node.falseBlock().isEmpty()) {
writeIndentedLine("else");
node.falseBlock().accept(this);
}
}
@Override
public void visit(CSLockStatement node) {
writeBlockStatement("lock", node);
}
@Override
public void visit(CSWhileStatement node) {
writeBlockStatement("while", node);
}
@Override
public void visit(CSSwitchStatement node) {
writeIndented("switch (");
node.expression().accept(this);
writeLine(")");
enterBody();
writeLineSeparatedList(node.caseClauses());
leaveBody();
}
@Override
public void visit(CSCaseClause node) {
int clauses = 0;
for (CSExpression e : node.expressions()) {
if (clauses++ > 0)
writeLine();
writeIndented("case ");
e.accept(this);
write(":");
}
if (node.isDefault()) {
if (clauses > 0)
writeLine();
writeIndented("default:");
}
writeLine();
node.body().accept(this);
}
@Override
public void visit(CSForEachStatement node) {
printPrecedingComments(node);
writeIndented("foreach (");
node.variable().accept(this);
write(" in ");
node.expression().accept(this);
writeLine(")");
node.body().accept(this);
}
@Override
public void visit(CSForStatement node) {
printPrecedingComments(node);
writeIndented("for (");
writeCommaSeparatedList(node.initializers());
write("; ");
if (null != node.expression()) {
node.expression().accept(this);
}
write("; ");
writeCommaSeparatedList(node.updaters());
writeLine(")");
node.body().accept(this);
}
@Override
public void visit(CSBreakStatement node) {
printPrecedingComments(node);
writeIndentedLine("break;");
}
@Override
public void visit(CSGotoStatement node) {
printPrecedingComments(node);
if (node.target() != null) {
writeIndented("goto case ");
node.target().accept(this);
write(";");
writeLine();
}
else
writeIndentedLine("goto " + node.label() + ";");
}
@Override
public void visit(CSContinueStatement node) {
printPrecedingComments(node);
writeIndentedLine("continue;");
}
private void writeBlockStatement(String keyword, CSBlockStatement node) {
printPrecedingComments(node);
writeIndented(keyword);
write(" (");
node.expression().accept(this);
write(")");
writeLine();
node.body().accept(this);
}
@Override
public void visit(CSDoStatement node) {
writeIndentedLine("do");
node.body().accept(this);
writeIndented("while (");
node.expression().accept(this);
writeLine(");");
}
@Override
public void visit(CSTryStatement node) {
printPrecedingComments(node);
writeIndentedLine("try");
node.body().accept(this);
visitList(node.catchClauses());
if (null != node.finallyBlock()) {
writeIndentedLine("finally");
node.finallyBlock().accept(this);
}
}
@Override
public void visit(CSCatchClause node) {
writeIndented("catch");
CSVariableDeclaration ex = node.exception();
if (ex != null) {
write(" (");
ex.accept(this);
write(")");
}
writeLine();
node.body().accept(this);
}
@Override
public void visit(CSThrowStatement node) {
printPrecedingComments(node);
if (null == node.expression()) {
writeIndentedLine("throw;");
} else {
writeIndented("throw ");
node.expression().accept(this);
writeLine(";");
}
}
@Override
public void visit(CSExpressionStatement node) {
printPrecedingComments(node);
writeIndentation();
node.expression().accept(this);
writeLine(";");
}
@Override
public void visit(CSParenthesizedExpression node) {
write("(");
node.expression().accept(this);
write(")");
}
@Override
public void visit(CSConditionalExpression node) {
node.expression().accept(this);
write(" ? ");
node.trueExpression().accept(this);
write(" : ");
node.falseExpression().accept(this);
}
@Override
public void visit(CSInfixExpression node) {
node.lhs().accept(this);
write(" ");
write(node.operator());
write(" ");
node.rhs().accept(this);
}
@Override
public void visit(CSPrefixExpression node) {
write(node.operator());
node.operand().accept(this);
}
@Override
public void visit(CSPostfixExpression node) {
node.operand().accept(this);
write(node.operator());
}
@Override
public void visit(CSConstructorInvocationExpression node) {
write("new ");
writeMethodInvocation(node);
}
@Override
public void visit(CSMethodInvocationExpression node) {
writeMethodInvocation(node);
}
protected void writeMethodInvocation(CSMethodInvocationExpression node) {
node.expression().accept(this);
writeTypeArguments(node);
writeParameterList(node.arguments());
}
@Override
public void visit(CSNumberLiteralExpression node) {
write(node.token());
}
@Override
public void visit(CSUncheckedExpression node) {
write("unchecked(");
node.expression().accept(this);
write(")");
}
@Override
public void visit(CSTypeofExpression node) {
write("typeof(");
node.type().accept(this);
write(")");
}
@Override
public void visit(CSBoolLiteralExpression node) {
write(Boolean.toString(node.booleanValue()));
}
@Override
public void visit(CSStringLiteralExpression node) {
write(node.escapedValue());
}
@Override
public void visit(CSCharLiteralExpression node) {
write(node.escapedValue());
}
@Override
public void visit(CSNullLiteralExpression node) {
write("null");
}
@Override
public void visit(CSBaseExpression node) {
write("base");
}
@Override
public void visit(CSThisExpression node) {
write("this");
}
@Override
public void visit(CSArrayCreationExpression node) {
write("new ");
CSharpTypeReferenceVisitor arrayElementTypeVisitor = new CSharpTypeReferenceVisitor(this);
node.elementType().accept(arrayElementTypeVisitor);
write("[");
if (null != node.length()) {
node.length().accept(this);
}
write("]");
write(arrayElementTypeVisitor.sufix());
if (null != node.initializer()) {
write(" ");
node.initializer().accept(this);
}
}
@Override
public void visit(CSArrayInitializerExpression node) {
write("{ ");
writeCommaSeparatedList(filterRemovedExpressions(node.expressions()));
write(" }");
}
private Iterable<CSNode> filterRemovedExpressions(List<CSExpression> expressions) {
final ArrayList<CSNode> result = new ArrayList<CSNode>(expressions.size());
for (CSNode e : expressions)
if (!(e instanceof CSRemovedExpression))
result.add(e);
return result;
}
@Override
public void visit(CSIndexedExpression node) {
node.expression().accept(this);
write("[");
writeCommaSeparatedList(node.indexes());
write("]");
}
@Override
public void visit(CSCastExpression node) {
write("(");
node.type().accept(this);
write(")");
if (null != node.expression()) {
node.expression().accept(this);
}
}
@Override
public void visit(CSReferenceExpression node) {
write(node.name());
}
@Override
public void visit(CSMemberReferenceExpression node) {
node.expression().accept(this);
write(".");
write(node.name());
}
@Override
public void visit(CSByRefExpression node) {
if (node.isOut())
write("out ");
else
write("ref ");
node.expression().accept(this);
}
protected void writeParameterList(CSMethodBase node) {
List<CSVariableDeclaration> parameters = node.parameters();
write("(");
if (node.isVarArgs()) {
if (parameters.size() > 1) {
writeCommaSeparatedList(parameters.subList(0, parameters.size() - 1));
write(", ");
}
write("params ");
visit(parameters.get(parameters.size() - 1));
} else {
writeCommaSeparatedList(parameters);
}
write(")");
}
protected <T extends CSNode> void writeParameterList(Iterable<T> parameters) {
write("(");
writeCommaSeparatedList(parameters);
write(")");
}
@Override
public void visit(CSField node) {
writeMemberHeader(node);
writeFieldModifiers(node);
writeDeclaration(node.type(), node.name(), node.initializer());
}
@Override
public void visit(CSProperty node) {
writeMetaMemberHeader(node);
node.type().accept(this);
write(" ");
if (node.isIndexer()) {
write("this[");
writeCommaSeparatedList(node.parameters());
writeLine("]");
} else {
writeLine(node.name());
}
enterBody();
writeOptionalMemberBlock("get", node.getter(), node.isAbstract());
writeOptionalMemberBlock("set", node.setter(), node.isAbstract());
leaveBody();
}
private void writeOptionalMemberBlock(final String name, final CSBlock block, boolean isAbstract) {
if (null != block) {
writeMemberBlock(name, block, isAbstract);
}
}
private void writeMemberHeader(CSMember node) {
writeDoc(node);
writeAttributes(node);
writeVisibility(node);
}
@Override
public void visit(CSEvent node) {
writeMetaMemberHeader(node);
write("event ");
node.type().accept(this);
write(" ");
write(node.name());
final CSBlock firstBlock = node.getAddBlock();
if (null == firstBlock) {
writeLine(";");
return;
}
writeLine();
enterBody();
writeMemberBlock("add", firstBlock, node.isAbstract());
writeMemberBlock("remove", node.getRemoveBlock(), node.isAbstract());
leaveBody();
}
private void writeMetaMemberHeader(CSMetaMember node) {
writeDoc(node);
writeAttributes(node);
writeMethodHeader(node, node.modifier());
}
private void writeMemberBlock(String name, CSBlock block, boolean isAbstract) {
writeIndented(name);
if (isAbstract) {
writeLine(";");
} else {
writeLine();
block.accept(this);
}
}
@Override
public void visit(CSAttribute node) {
writeIndented("[");
write(node.name());
if (!node.arguments().isEmpty()) {
writeParameterList(node.arguments());
}
writeLine("]");
}
@Override
public void visit(CSLabelStatement node) {
// labels can't be free-standing, for simplicity simply emit an
// empty statement
writeLine(node.label() + ": ;");
}
@Override
public void visit(CSDocTextOverlay node) {
writeXmlDoc(node.text());
}
@Override
public void visit(CSDocTextNode node) {
writeXmlDoc(xmlEscape(node.text()));
}
private void writeXmlDoc(final String xmldocText) {
String[] lines = xmldocText.split("\n");
for (int i = 0; i < lines.length; ++i) {
if (i > 0) {
writeLine();
writeIndentation();
}
writeBlock(lines[i].trim().replace("<br>", "<br />"));
}
}
private String xmlEscape(String text) {
return text.replaceAll("(<)(/?[^\\s][^>]*)(>)", ":lt:$2:gt:")
.replace("<", "<").replace(">", ">")
.replace(":lt:", "<")
.replace(":gt:", ">");
}
@Override
public void visit(CSDocTagNode node) {
String tagName = node.tagName();
List<CSDocAttributeNode> attributes = node.attributes();
List<CSDocNode> fragments = node.fragments();
write("<");
write(tagName);
if (!attributes.isEmpty()) {
for (CSDocAttributeNode attr : attributes) {
write(" ");
write(attr.name());
write("=\"");
write(attr.value());
write("\"");
}
}
write(">");
if (fragments.size() > 1) {
writeLine();
for (CSDocNode f : fragments) {
writeIndentation();
f.accept(this);
writeLine();
}
writeIndented("</" + tagName + ">");
} else {
if (!fragments.isEmpty()) {
fragments.get(0).accept(this);
}
write("</" + tagName + ">");
}
}
private void writeAttributes(CSMember node) {
visitList(node.attributes());
}
private void writeFieldModifiers(CSField node) {
for (CSFieldModifier m : node.modifiers()) {
write(m.toString().toLowerCase());
write(" ");
}
}
private void writeDoc(CSMember node) {
List<CSDocNode> docs = node.docs();
if (docs.isEmpty()) {
return;
}
linePrefix("/// ");
for (CSDocNode doc : docs) {
writeIndentation();
doc.accept(this);
writeLine();
}
linePrefix(null);
}
private String methodModifier(CSMethodModifier modifier) {
switch (modifier) {
case Static:
return "static ";
case Virtual:
return "virtual ";
case Abstract:
return "abstract ";
case AbstractOverride:
return "abstract override ";
case Sealed:
return "sealed override ";
case Override:
return "override ";
case Extern:
return "static extern ";
}
return "";
}
interface Closure {
void execute();
}
private <T extends CSNode> void writeLineSeparatedList(Iterable<T> nodes) {
writeSeparatedList(nodes, new Closure() {
public void execute() {
writeLine();
}
});
}
private <T extends CSNode> void writeCommaSeparatedList(Iterable<T> nodes) {
writeList(nodes, ", ");
}
private <T extends CSNode> void writeList(Iterable<T> nodes, final String separator) {
writeSeparatedList(nodes, new Closure() {
public void execute() {
write(separator);
}
});
}
private <T extends CSNode> void writeSeparatedList(Iterable<T> nodes, Closure separator) {
Iterator<T> iterator = nodes.iterator();
if (!iterator.hasNext())
return;
iterator.next().accept(this);
while (iterator.hasNext()) {
separator.execute();
iterator.next().accept(this);
}
}
private String classModifier(CSClassModifier modifier) {
switch (modifier) {
case Abstract:
return "abstract ";
case Sealed:
return "sealed ";
case Static:
return "static ";
}
return "";
}
protected void enterBody() {
// writeLine();
writeIndentedLine("{");
indent();
}
private void indent() {
_writer.indent();
}
private void outdent() {
_writer.outdent();
}
private void writeIndentation() {
_writer.writeIndentation();
}
private void writeIndented(String s) {
_writer.writeIndented(s);
}
private void writeIndentedLine(String s) {
_writer.writeIndentedLine(s);
}
private void write(String s) {
_writer.write(s);
}
private void linePrefix(String s) {
_writer.linePrefix(s);
}
private void writeBlock(String s) {
_writer.writeBlock(s);
}
private void writeLine(String s) {
_writer.writeLine(s);
}
private void writeLine() {
_writer.writeLine();
}
protected void leaveBody() {
outdent();
writeIndentedLine("}");
}
class CSharpTypeReferenceVisitor extends CSVisitor {
private CSVisitor _delegate;
private StringBuffer _sb = new StringBuffer();
CSharpTypeReferenceVisitor(CSVisitor delegate) {
_delegate = delegate;
}
@Override
public void visit(CSArrayTypeReference node) {
node.elementType().accept(_delegate);
for (int i = 0; i < node.dimensions(); ++i) {
_sb.append("[]");
}
}
public void visit(CSTypeReferenceExpression node) {
node.accept(_delegate);
}
@Override
public void visit(CSTypeReference node) {
node.accept(_delegate);
}
@Override
public void visit(CSNestedTypeReference node) {
node.accept(_delegate);
}
@Override
public void visit(CSNullableTypeReference node) {
node.accept(_delegate);
}
@Override
public void visit(CSByRefTypeReference node) {
node.accept(_delegate);
}
String sufix() {
return _sb.toString();
}
}
@Override
public void visit(CSUserDefinedConversion node) {
printPrecedingComments(node);
beginEnclosingIfDefs(node);
writeDoc(node);
writeAttributes(node);
writeIndentation();
write("public static ");
write(node.implicit() ? "implicit" : "explicit");
write(" operator ");
node.targetType().accept(this);
write("(");
node.sourceType().accept(this);
write(" ");
write("source");
write(")");
writeLine();
node.body().accept(this);
endEnclosingIfDefs(node);
}
@Override
public void visit(CSDefaultExpression node) {
write("default");
write("(");
write(node.name());
write(")");
}
}