Added AcceleoAstSerializer.
Change-Id: Ib40bc09a54bd1ee472540b0e7bd474a8e849d8e9
diff --git a/acceleo-aql/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/parser/AcceleoAstSerializer.java b/acceleo-aql/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/parser/AcceleoAstSerializer.java
new file mode 100644
index 0000000..205f255
--- /dev/null
+++ b/acceleo-aql/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/parser/AcceleoAstSerializer.java
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.aql.parser;
+
+import org.eclipse.acceleo.ASTNode;
+import org.eclipse.acceleo.Binding;
+import org.eclipse.acceleo.Block;
+import org.eclipse.acceleo.Comment;
+import org.eclipse.acceleo.CommentBody;
+import org.eclipse.acceleo.Documentation;
+import org.eclipse.acceleo.Expression;
+import org.eclipse.acceleo.ExpressionStatement;
+import org.eclipse.acceleo.FileStatement;
+import org.eclipse.acceleo.ForStatement;
+import org.eclipse.acceleo.IfStatement;
+import org.eclipse.acceleo.Import;
+import org.eclipse.acceleo.LetStatement;
+import org.eclipse.acceleo.Metamodel;
+import org.eclipse.acceleo.Module;
+import org.eclipse.acceleo.ModuleDocumentation;
+import org.eclipse.acceleo.ModuleElement;
+import org.eclipse.acceleo.ModuleElementDocumentation;
+import org.eclipse.acceleo.ModuleReference;
+import org.eclipse.acceleo.ProtectedArea;
+import org.eclipse.acceleo.Query;
+import org.eclipse.acceleo.Statement;
+import org.eclipse.acceleo.Template;
+import org.eclipse.acceleo.TextStatement;
+import org.eclipse.acceleo.Variable;
+import org.eclipse.acceleo.query.parser.AstSerializer;
+import org.eclipse.acceleo.util.AcceleoSwitch;
+
+/**
+ * Serializes {@link ASTNode}.
+ *
+ * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
+ */
+public class AcceleoAstSerializer extends AcceleoSwitch<Object> {
+
+ /**
+ * A space.
+ */
+ private static final String SPACE = " ";
+
+ /**
+ * A dummy {@link Object} to prevent switching in super types.
+ */
+ private static final Object DUMMY = new Object();
+
+ /**
+ * The {@link AstSerializer}.
+ */
+ private AstSerializer querySerializer = new AstSerializer();
+
+ /**
+ * The resulting {@link StringBuilder}.
+ */
+ private StringBuilder builder;
+
+ /**
+ * The current binding separator.
+ */
+ private String bindingSeparator;
+
+ /**
+ * Serializes the given {@link ASTNode}.
+ *
+ * @param node
+ * the {@link ASTNode}
+ * @return the serialized {@link ASTNode}
+ */
+ public String serialize(ASTNode node) {
+ builder = new StringBuilder();
+
+ doSwitch(node);
+
+ return builder.toString();
+ }
+
+ @Override
+ public Object caseBinding(Binding binding) {
+ builder.append(binding.getName());
+ builder.append(" : ");
+ if (binding.getType() != null) {
+ builder.append(querySerializer.serialize(binding.getType().getAst()));
+ }
+ builder.append(SPACE);
+ builder.append(bindingSeparator);
+ builder.append(SPACE);
+ doSwitch(binding.getInitExpression());
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseBlock(Block block) {
+ for (Statement statement : block.getStatements()) {
+ doSwitch(statement);
+ }
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseComment(Comment comment) {
+
+ builder.append(AcceleoParser.COMMENT_START);
+ doSwitch(comment.getBody());
+ builder.append(AcceleoParser.COMMENT_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseCommentBody(CommentBody commentBody) {
+ builder.append(commentBody.getValue());
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseDocumentation(Documentation documentation) {
+
+ builder.append(AcceleoParser.DOCUMENTATION_START);
+ doSwitch(documentation.getBody());
+ builder.append(AcceleoParser.DOCUMENTATION_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseExpression(Expression expression) {
+ builder.append(querySerializer.serialize(expression.getAst().getAst()));
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseExpressionStatement(ExpressionStatement expressionStatement) {
+ doSwitch(expressionStatement.getExpression());
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseFileStatement(FileStatement fileStatement) {
+ builder.append(AcceleoParser.FILE_HEADER_START);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ doSwitch(fileStatement.getUrl());
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ builder.append(fileStatement.getMode().getName());
+ if (fileStatement.getCharset() != null) {
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ doSwitch(fileStatement.getCharset());
+ }
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(AcceleoParser.FILE_HEADER_END);
+ doSwitch(fileStatement.getBody());
+ builder.append(AcceleoParser.FILE_END);
+
+ return DUMMY;
+ };
+
+ @Override
+ public Object caseForStatement(ForStatement forStatement) {
+ builder.append(AcceleoParser.FOR_HEADER_START);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ bindingSeparator = AcceleoParser.PIPE;
+ doSwitch(forStatement.getBinding());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ // TODO sperator()
+ builder.append(AcceleoParser.FOR_HEADER_END);
+ doSwitch(forStatement.getBody());
+ builder.append(AcceleoParser.FOR_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseIfStatement(IfStatement ifStatement) {
+ builder.append(AcceleoParser.IF_HEADER_START);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ doSwitch(ifStatement.getCondition());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(AcceleoParser.IF_HEADER_END);
+ if (ifStatement.getThen() != null) {
+ doSwitch(ifStatement.getElse());
+ }
+ if (ifStatement.getElse() != null) {
+ final Block elseBlock = ifStatement.getElse();
+ generateElse(elseBlock);
+ }
+ builder.append(AcceleoParser.IF_END);
+
+ return DUMMY;
+ }
+
+ /**
+ * Serializes the given {@link Block} as a elseif or a else.
+ *
+ * @param block
+ * the {@link Block}
+ */
+ private void generateElse(Block block) {
+ if (block.getStatements().size() == 1 && block.getStatements().get(0) instanceof IfStatement) {
+ final IfStatement ifStatement = (IfStatement)block.getStatements().get(0);
+ builder.append(AcceleoParser.IF_ELSEIF);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ doSwitch(ifStatement.getCondition());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(AcceleoParser.IF_HEADER_END);
+ doSwitch(ifStatement.getThen());
+ if (ifStatement.getElse() != null) {
+ final Block elseBlock = ifStatement.getElse();
+ generateElse(elseBlock);
+ }
+ } else {
+ builder.append(AcceleoParser.IF_ELSE);
+ doSwitch(block);
+ }
+ }
+
+ @Override
+ public Object caseImport(Import imp) {
+ builder.append(AcceleoParser.IMPORT_START);
+ doSwitch(imp.getModule());
+ builder.append(AcceleoParser.IMPORT_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseLetStatement(LetStatement letStatement) {
+ builder.append(AcceleoParser.LET_HEADER_START);
+ if (!letStatement.getVariables().isEmpty()) {
+ final StringBuilder previousBuilder = builder;
+ try {
+ builder = new StringBuilder();
+ bindingSeparator = AcceleoParser.EQUAL;
+ for (Binding binding : letStatement.getVariables()) {
+ doSwitch(binding);
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ }
+ previousBuilder.append(builder.substring(0, builder.length() - 2));
+ } finally {
+ builder = previousBuilder;
+ }
+ }
+ builder.append(AcceleoParser.LET_HEADER_END);
+ doSwitch(letStatement.getBody());
+ builder.append(AcceleoParser.LET_END);
+
+ return DUMMY;
+ };
+
+ @Override
+ public Object caseMetamodel(Metamodel metamodel) {
+ builder.append(AcceleoParser.QUOTE);
+ builder.append(metamodel.getReferencedPackage().getNsURI());
+ builder.append(AcceleoParser.QUOTE);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseModule(Module module) {
+ builder.append(AcceleoParser.MODULE_HEADER_START);
+ builder.append(module.getName());
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ if (!module.getMetamodels().isEmpty()) {
+ final StringBuilder previousBuilder = builder;
+ try {
+ builder = new StringBuilder();
+ for (Metamodel metamodel : module.getMetamodels()) {
+ doSwitch(metamodel);
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ }
+ previousBuilder.append(builder.substring(0, builder.length() - 2));
+ } finally {
+ builder = previousBuilder;
+ }
+ }
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ if (module.getExtends() != null) {
+ builder.append(SPACE);
+ builder.append(AcceleoParser.EXTENDS);
+ doSwitch(module.getExtends());
+ }
+ builder.append(AcceleoParser.MODULE_HEADER_END);
+
+ for (ModuleElement moduleElement : module.getModuleElements()) {
+ builder.append("\n");
+ doSwitch(moduleElement);
+ builder.append("\n");
+ }
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseModuleDocumentation(ModuleDocumentation moduleDocumentation) {
+ builder.append(AcceleoParser.DOCUMENTATION_START);
+ doSwitch(moduleDocumentation.getBody());
+ builder.append(AcceleoParser.DOCUMENTATION_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseModuleElementDocumentation(ModuleElementDocumentation moduleElementDocumentation) {
+ builder.append(AcceleoParser.DOCUMENTATION_START);
+ doSwitch(moduleElementDocumentation.getBody());
+ builder.append(AcceleoParser.DOCUMENTATION_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseModuleReference(ModuleReference moduleReference) {
+ builder.append(moduleReference.getQualifiedName());
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseProtectedArea(ProtectedArea protectedArea) {
+ builder.append(AcceleoParser.PROTECTED_AREA_HEADER_START);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ doSwitch(protectedArea.getId());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(AcceleoParser.PROTECTED_AREA_HEADER_END);
+ doSwitch(protectedArea.getBody());
+ builder.append(AcceleoParser.PROTECTED_AREA_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseQuery(Query query) {
+ builder.append(AcceleoParser.QUERY_START);
+ builder.append(query.getVisibility());
+ builder.append(SPACE);
+ builder.append(query.getName());
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ if (!query.getParameters().isEmpty()) {
+ final StringBuilder previousBuilder = builder;
+ try {
+ builder = new StringBuilder();
+ for (Variable parameter : query.getParameters()) {
+ doSwitch(parameter);
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ }
+ previousBuilder.append(builder.substring(0, builder.length() - 2));
+ } finally {
+ builder = previousBuilder;
+ }
+ }
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(SPACE);
+ if (query.getType() != null) {
+ builder.append(AcceleoParser.COLON);
+ builder.append(SPACE);
+ builder.append(querySerializer.serialize(query.getType().getAst()));
+ builder.append(SPACE);
+ }
+ builder.append(AcceleoParser.EQUAL);
+ builder.append(SPACE);
+ doSwitch(query.getBody());
+ builder.append(AcceleoParser.QUERY_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseTemplate(Template template) {
+ builder.append(AcceleoParser.TEMPLATE_HEADER_START);
+ builder.append(template.getVisibility());
+ builder.append(SPACE);
+ builder.append(template.getName());
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ if (!template.getParameters().isEmpty()) {
+ final StringBuilder previousBuilder = builder;
+ try {
+ builder = new StringBuilder();
+ for (Variable parameter : template.getParameters()) {
+ doSwitch(parameter);
+ builder.append(AcceleoParser.COMMA);
+ builder.append(SPACE);
+ }
+ previousBuilder.append(builder.substring(0, builder.length() - 2));
+ } finally {
+ builder = previousBuilder;
+ }
+ }
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ if (template.getGuard() != null) {
+ builder.append(SPACE);
+ builder.append(AcceleoParser.TEMPLATE_GUARD);
+ builder.append(SPACE);
+ builder.append(AcceleoParser.OPEN_PARENTHESIS);
+ doSwitch(template.getGuard());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ }
+ if (template.getPost() != null) {
+ builder.append(SPACE);
+ builder.append(AcceleoParser.TEMPLATE_POST);
+ doSwitch(template.getPost());
+ builder.append(AcceleoParser.CLOSE_PARENTHESIS);
+ builder.append(SPACE);
+ }
+ builder.append(AcceleoParser.TEMPLATE_HEADER_END);
+ doSwitch(template.getBody());
+ builder.append(AcceleoParser.TEMPLATE_END);
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseTextStatement(TextStatement textStatement) {
+ builder.append(textStatement.getValue());
+
+ return DUMMY;
+ }
+
+ @Override
+ public Object caseVariable(Variable variable) {
+ builder.append(variable.getName());
+ builder.append(SPACE);
+ builder.append(AcceleoParser.COLON);
+ builder.append(SPACE);
+ builder.append(querySerializer.serialize(variable.getType().getAst()));
+
+ return DUMMY;
+ }
+
+}