package sharpen.xobotos.api.interop; import sharpen.core.io.IndentedWriter; import sharpen.xobotos.api.interop.glue.*; import sharpen.xobotos.api.interop.glue.AbstractMember.Visibility; import sharpen.xobotos.api.interop.glue.ClassDefinition.MemberEntry; import sharpen.xobotos.api.interop.glue.ClassDefinition.MemberFilter; import sharpen.xobotos.api.interop.glue.Method.Flags; import java.util.List; public class Printer extends Visitor { private final IndentedWriter _writer; private String _currentClass = ""; public Printer(IndentedWriter writer) { this._writer = writer; } @Override public void visit(AbstractTypeReference node) { _writer.write(node.getTypeName()); } @Override public void visit(Parameter node) { node.getType().accept(this); _writer.write(" "); _writer.write(node.getName()); } @Override public void visit(Method node) { if (node.hasDeclaration()) { _writer.writeIndentation(); } else { if (node.getFlags() == Flags.EXPORT) { _writer.writeIndentation(); _writer.write("extern \"C\" DLL_EXPORT "); } else if (node.getFlags() == Flags.STATIC) { _writer.writeIndentation(); if (!node.hasDeclaration()) _writer.write("static "); } else { _writer.writeIndentation(); } } node.getReturnType().accept(this); _writer.writeLine(); _writer.writeIndentation(); _writer.write(_currentClass + node.getName()); _writer.write("("); visitCommaSeparatedList(node.getParameters()); _writer.writeLine(")"); node.getBody().accept(this); _writer.writeLine(); } @Override public void visit(Block node) { _writer.writeIndentation(); _writer.writeLine("{"); _writer.indent(); for (Statement stm : node.getStatements()) stm.accept(this); _writer.outdent(); _writer.writeIndentation(); _writer.writeLine("}"); } @Override public void visit(ExpressionStatement node) { _writer.writeIndentation(); node.getExpression().accept(this); _writer.writeLine(";"); } @Override public void visit(VariableReference node) { _writer.write(node.getVariable().getName()); } @Override public void visit(InstanceMemberAccess node) { node.getParent().accept(this); _writer.write("->"); _writer.write(node.getMember()); } @Override public void visit(StructMemberAccess node) { node.getParent().accept(this); _writer.write("."); _writer.write(node.getMember()); } @Override public void visit(StaticMemberAccess node) { node.getType().accept(this); _writer.write("::"); _writer.write(node.getMember()); } @Override public void visit(MethodInvocation node) { node.getExpression().accept(this); _writer.write("("); visitCommaSeparatedList(node.getArguments()); _writer.writeBlock(")"); } @Override public void visit(ConstructorInvocation node) { _writer.write("new "); node.getType().accept(this); _writer.write("("); visitCommaSeparatedList(node.getArguments()); _writer.writeBlock(")"); } @Override public void visit(DestructorInvocation node) { _writer.writeIndentation(); _writer.write("delete "); node.getExpression().accept(this); _writer.writeLine(";"); } @Override public void visit(ArrayDestructorInvocation node) { _writer.writeIndentation(); _writer.write("delete[] "); node.getExpression().accept(this); _writer.writeLine(";"); } @Override public void visit(UnaryOperator node) { _writer.write(node.getOperator()); node.getExpression().accept(this); } @Override public void visit(CastExpression node) { _writer.write("("); node.getType().accept(this); _writer.writeBlock(")"); node.getExpression().accept(this); } @Override public void visit(LiteralExpression node) { _writer.write(node.getValue()); } @Override public void visit(ReferenceExpression node) { _writer.write(node.getName()); } @Override public void visit(ConditionalExpression node) { node.getCondition().accept(this); _writer.write(" ? "); node.getTrueExpression().accept(this); _writer.write(" : "); node.getFalseExpression().accept(this); } @Override public void visit(TemplateFunctionReference node) { _writer.write(node.getName()); _writer.write("<"); visitCommaSeparatedList(node.getArguments()); _writer.writeBlock(">"); } @Override public void visit(LocalVariable node) { _writer.writeIndentation(); node.getType().accept(this); _writer.write(" "); _writer.write(node.getName()); if (node.getInitializer() != null) { _writer.write(" = "); node.getInitializer().accept(this); } _writer.writeLine(";"); } @Override public void visit(AssignmentStatement node) { _writer.writeIndentation(); node.getTarget().accept(this); _writer.write(" = "); node.getSource().accept(this); _writer.writeLine(";"); } @Override public void visit(ReturnStatement node) { _writer.writeIndentation(); _writer.write("return"); if (node.hasReturnValue()) { _writer.write(" "); node.getExpression().accept(this); } _writer.writeLine(";"); } @Override public void visit(StructDefinition node) { _writer.write("struct "); _writer.writeLine(node.getName()); _writer.writeLine("{"); _writer.indent(); for (AbstractDefinition member : node.getMembers()) { member.accept(this); } _writer.outdent(); _writer.writeLine("};"); _writer.writeLine(); } @Override public void visit(ClassDefinition node) { if (node.hasDeclaration()) { final String oldClass = _currentClass; _currentClass = _currentClass + node.getName() + "::"; writeMemberList(node, null); _currentClass = oldClass; } else { _writer.write("class "); _writer.writeLine(node.getName()); _writer.writeLine("{"); _writer.indent(); writeMemberList(node, Visibility.PUBLIC); writeMemberList(node, Visibility.PROTECTED); writeMemberList(node, Visibility.PRIVATE); _writer.outdent(); _writer.writeLine("};"); _writer.writeLine(); } } @Override public void visit(Field node) { if (node.hasDeclaration()) return; _writer.writeIndentation(); node.getType().accept(this); _writer.write(" "); _writer.write(node.getName()); _writer.writeLine(";"); } @Override public void visit(Constructor node) { _writer.writeIndentation(); _writer.write(_currentClass); node.getType().accept(this); _writer.write("("); visitCommaSeparatedList(node.getParameters()); _writer.writeLine(")"); node.getBody().accept(this); _writer.writeLine(); } @Override public void visit(Destructor node) { _writer.writeIndentation(); _writer.writeBlock("~"); node.getType().accept(this); _writer.write("("); visitCommaSeparatedList(node.getParameters()); _writer.writeLine(")"); node.getBody().accept(this); _writer.writeLine(); } @Override public void visit(BinaryOperator node) { node.getLeftExpression().accept(this); _writer.write(" "); _writer.write(node.getOperator()); _writer.write(" "); node.getRightExpression().accept(this); } @Override public void visit(IfStatement node) { _writer.writeIndentation(); _writer.write("if ("); node.getCondition().accept(this); _writer.writeLine(")"); node.getThenBlock().accept(this); if (!node.getElseBlock().isEmpty()) { _writer.writeIndentation(); _writer.writeLine("else"); node.getElseBlock().accept(this); } } @Override public void visit(ForStatement node) { _writer.writeIndentation(); _writer.write("for("); if (node.getVariable() != null) { node.getVariable().getType().accept(this); _writer.write(" "); _writer.write(node.getVariable().getName()); _writer.write(" = "); } node.getInitializer().accept(this); _writer.writeBlock(";"); _writer.writeSpace(); node.getCheck().accept(this); _writer.writeBlock(";"); _writer.writeSpace(); node.getUpdate().accept(this); _writer.writeLine(")"); node.getBody().accept(this); } @Override public void visit(PostfixIncrement node) { _writer.write(node.getVariable().getName()); _writer.writeBlock("++"); } @Override public void visit(IndexedExpression node) { node.getExpression().accept(this); _writer.write("["); node.getIndex().accept(this); _writer.writeBlock("]"); } @Override public void visit(ParenthesizedExpression node) { _writer.write("("); node.getExpression().accept(this); _writer.writeBlock(")"); } @Override public void visit(ArrayCreationExpression node) { _writer.write("new "); node.getType().accept(this); _writer.write("["); node.getSize().accept(this); _writer.writeBlock("]"); } @Override public void visit(CompilationUnit node) { node.getIncludeSection().accept(this); _writer.writeLine(); visitList(node.getMembers()); _writer.writeLine(); visitList(node.getMethods()); } @Override public void visit(CompilationUnitHeader node) { _writer.writeLine("#ifndef " + node.getConditional()); _writer.writeLine("#define " + node.getConditional() + " 1"); _writer.writeLine(); node.getIncludeSection().accept(this); _writer.writeLine(); visitList(node.getMembers()); _writer.writeLine(); visitList(node.getMethods()); _writer.writeLine(); _writer.writeLine("#endif"); } @Override public void visit(IncludeDirective node) { _writer.write("#include "); if (node.searchPath()) _writer.writeLine("<" + node.getName() + ">"); else _writer.writeLine("\"" + node.getName() + "\""); } @Override public void visit(IncludeSection node) { visitList(node.getIncludes()); } @Override public void visit(ClassDeclaration node) { final ClassDefinition klass = node.getDefinition(); _writer.write("class "); _writer.writeLine(klass.getName()); _writer.writeLine("{"); writeDeclarationList(klass, Visibility.PUBLIC); writeDeclarationList(klass, Visibility.PROTECTED); writeDeclarationList(klass, Visibility.PRIVATE); _writer.writeLine("};"); _writer.writeLine(); } @Override public void visit(StructDeclaration node) { _writer.write("struct "); _writer.write(node.getDefinition().getName()); _writer.writeLine(";"); _writer.writeLine(); } @Override public void visit(FieldDeclaration node) { final Field field = node.getDefinition(); _writer.writeIndentation(); field.getType().accept(this); _writer.write(" "); _writer.write(field.getName()); _writer.writeLine(";"); } @Override public void visit(ConstructorDeclaration node) { final Constructor ctor = node.getDefinition(); _writer.writeIndentation(); ctor.getType().accept(this); _writer.write("("); visitCommaSeparatedList(ctor.getParameters()); _writer.writeLine(");"); } @Override public void visit(MethodDeclaration node) { final Method method = node.getDefinition(); if (method.getFlags() == Flags.EXPORT) { _writer.writeIndentation(); _writer.write("extern \"C\" DLL_EXPORT "); } else if (method.getFlags() == Flags.STATIC) { _writer.writeIndentation(); _writer.write("static "); } else { _writer.writeIndentation(); } method.getReturnType().accept(this); _writer.write(" "); _writer.write(method.getName()); _writer.write("("); visitCommaSeparatedList(method.getParameters()); _writer.writeLine(");"); } @Override public void visit(DestructorDeclaration node) { final Destructor dtor = node.getDefinition(); _writer.writeIndentation(); _writer.writeBlock("~"); dtor.getType().accept(this); _writer.write("("); visitCommaSeparatedList(dtor.getParameters()); _writer.writeLine(");"); } private <T extends Node> void visitCommaSeparatedList(List<T> list) { if (list == null) return; boolean first = true; for (T item : list) { if (first) first = false; else { _writer.writeBlock(","); _writer.writeSpace(); } item.accept(this); } } private <T extends Node> void visitList(List<T> list) { if (list == null) return; for (T item : list) { item.accept(this); } } private void writeMemberList(final ClassDefinition node, final Visibility visibility) { List<MemberEntry> members = node.getMembers(new MemberFilter() { @Override public boolean filter(MemberEntry entry) { if ((visibility != null) && (entry.Visibility != visibility)) return false; if (node.hasDeclaration() && (entry.Definition == null)) return false; return true; } }); if (members.size() == 0) return; if (visibility != null) writeVisibility(visibility); for (MemberEntry member : members) { if (member.Definition != null) member.Definition.accept(this); else member.Declaration.accept(this); } _writer.writeLine(); } private void writeDeclarationList(ClassDefinition node, final Visibility visibility) { List<MemberEntry> members = node.getMembers(new MemberFilter() { @Override public boolean filter(MemberEntry entry) { return (entry.Declaration != null) && (entry.Visibility == visibility); } }); if (members.size() == 0) return; writeVisibility(visibility); _writer.indent(); for (MemberEntry member : members) member.Declaration.accept(this); _writer.outdent(); _writer.writeLine(); } private void writeVisibility(Visibility visibility) { switch (visibility) { case PUBLIC: _writer.writeLine("public:"); break; case PROTECTED: _writer.writeLine("protected:"); break; case PRIVATE: _writer.writeLine("private:"); break; } } }