All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.epsilon.eol.parse.EolUnparser Maven / Gradle / Ivy

/*********************************************************************
 * Copyright (c) 2020 The University of York.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.epsilon.eol.parse;

import java.util.Iterator;
import java.util.Map.Entry;
import org.eclipse.epsilon.eol.EolModule;
import org.eclipse.epsilon.eol.dom.*;

public class EolUnparser implements IEolVisitor {
	
	protected StringBuffer buffer = new StringBuffer();
	protected EolModule module = null;
	protected int indentation = 0;
	
	public String unparse(EolModule module) {
		
		this.module = module;
		buffer = new StringBuffer();
		
		module.getImports().stream().forEach(i -> {i.accept(this); newline();});
		module.getDeclaredModelDeclarations().stream().forEach(md -> {md.accept(this); newline();});
		unparseMain();
		module.getDeclaredOperations().stream().forEach(o -> {newline(); o.accept(this);});
		
		return buffer.toString();
	}
	
	public String getCode() {
		return buffer.toString();
	}
	
	protected void unparseMain() {
		module.getMain().accept(this);
	}
	
	protected void newline() {
		buffer.append(System.lineSeparator());
	}
	
	protected void comma() {
		buffer.append(", ");
	}
	
	protected void space() {
		buffer.append(' ');
	}
	
	protected void startCurlybrace() {
		buffer.append('{');
	}
	
	protected void endCurlybrace() {
		buffer.append('}');
	}
	
	protected void plusIndentationAndAppend() {
		++indentation;
		indent();
	}
	
	protected void minusIndentationAndAppend() {
		--indentation;
		indent();
	}
	
	protected void spaceCurlybraceNewlineIndent() {
		space();
		startCurlybrace();
		newline();
		plusIndentationAndAppend();
	}
	
	protected void newlineUnindentCurlybrace() {
		newline();
		minusIndentationAndAppend();
		endCurlybrace();
	}
	
	
	@Override
	public void visit(AbortStatement abortStatement) {
		buffer.append("abort;");
	}

	@Override
	public void visit(AndOperatorExpression andOperatorExpression) {
		unparseBinaryOperatorExpression(andOperatorExpression, "and");
	}

	@Override
	public void visit(DeleteStatement deleteStatement) {
		buffer.append("delete ");
		if (deleteStatement.getExpression() != null) {
			deleteStatement.getExpression().accept(this);
		}
		semicolon();
	}
	
	protected void semicolon() {
		buffer.append(";");
	}



	@Override
	public void visit(AssignmentStatement assignmentStatement) {
		assignmentStatement.getTargetExpression().accept(this);
		buffer.append(" = ");
		assignmentStatement.getValueExpression().accept(this);
		buffer.append(";");
	}

	@Override
	public void visit(BooleanLiteral booleanLiteral) {
		buffer.append(booleanLiteral.getValue());
	}

	@Override
	public void visit(BreakStatement breakStatement) {
		buffer.append(breakStatement.isAll() ? "breakAll" : "break");
		semicolon();
	}

	@Override
	public void visit(Case case_) {
		if (case_.getCondition() != null) {
			buffer.append("case ");
			case_.getCondition().accept(this);
		}
		else buffer.append("default");
		buffer.append(": ");
		case_.getBody().accept(this);
	}

	@Override
	public void visit(CollectionLiteralExpression collectionLiteralExpression) {
		buffer.append(collectionLiteralExpression.getCollectionType() + "{");
		Iterator li = collectionLiteralExpression.getParameterExpressions().iterator();
		while (li.hasNext()) {
			li.next().accept(this);
			if (li.hasNext()) {
				if (collectionLiteralExpression.isRange()) {
					buffer.append("..");
				}
				else {
					comma();
				}
			}
		}
		buffer.append("}");
	}

	@Override
	public void visit(ComplexOperationCallExpression complexOperationCallExpression) {
		// TODO Auto-generated method stub
	}

	@Override
	public void visit(ContinueStatement continueStatement) {
		buffer.append("continue;");
	}

	@Override
	public void visit(DivOperatorExpression divOperatorExpression) {
		unparseBinaryOperatorExpression(divOperatorExpression, "/");
	}

	@Override
	public void visit(DoubleEqualsOperatorExpression doubleEqualsOperatorExpression) {
		unparseBinaryOperatorExpression(doubleEqualsOperatorExpression, "==");
	}

	@Override
	public void visit(ElvisOperatorExpression elvisOperatorExpression) {
		elvisOperatorExpression.getFirstOperand().accept(this);
		buffer.append(" ?: ");
		elvisOperatorExpression.getSecondOperand().accept(this);
	}

	@Override
	public void visit(EnumerationLiteralExpression enumerationLiteralExpression) {
		buffer.append(enumerationLiteralExpression.getEnumerationLiteral());
	}

	@Override
	public void visit(EqualsOperatorExpression equalsOperatorExpression) {
		unparseBinaryOperatorExpression(equalsOperatorExpression, "=");
	}

	@Override
	public void visit(ExecutableBlock executableBlock) {
		// No need to implement for EOL itself
	}

	@Override
	public void visit(ExpressionInBrackets expressionInBrackets) {
		buffer.append("(");
		unparse(expressionInBrackets.getExpression());
		buffer.append(")");
	}

	@Override
	public void visit(ExpressionStatement expressionStatement) {
		unparse(expressionStatement.getExpression());
		semicolon();
	}
	
	protected void unparse(Expression expression) {
		if (expression != null) expression.accept(this);
	}
	
	@Override
	public void visit(FirstOrderOperationCallExpression operationCallExpression) {
		unparse(operationCallExpression.getTargetExpression());
		arrowOrDot(operationCallExpression);
		buffer.append(operationCallExpression.getName() + "(");
		Iterator pi = operationCallExpression.getParameters().iterator();
		while (pi.hasNext()) {
			pi.next().accept(this);
			if (pi.hasNext()) comma();
		}
		if (!operationCallExpression.getExpressions().isEmpty()) {
			buffer.append("|");
			Iterator ei = operationCallExpression.getExpressions().iterator();
			while (ei.hasNext()) {
				ei.next().accept(this);
				if (ei.hasNext()) comma();
			}
		}
		buffer.append(")");
	}

	@Override
	public void visit(ForStatement forStatement) {
		buffer.append("for (");
		forStatement.getIteratorParameter().accept(this);
		buffer.append(" in ");
		forStatement.getIteratedExpression().accept(this);
		buffer.append(") ");
		forStatement.getBodyStatementBlock().accept(this);
	}

	@Override
	public void visit(GreaterEqualOperatorExpression greaterEqualOperatorExpression) {
		unparseBinaryOperatorExpression(greaterEqualOperatorExpression, ">=");
	}

	@Override
	public void visit(GreaterThanOperatorExpression greaterThanOperatorExpression) {
		unparseBinaryOperatorExpression(greaterThanOperatorExpression, ">");
	}

	@Override
	public void visit(IfStatement ifStatement) {
		buffer.append("if (");
		unparse(ifStatement.getConditionExpression());
		buffer.append(") ");
		ifStatement.getThenStatementBlock().accept(this);
		if (ifStatement.getElseStatementBlock() != null) {
			newline();
			indent();
			buffer.append("else ");
			StatementBlock elseStatementBlock = ifStatement.getElseStatementBlock();
			if (elseStatementBlock.getStatements().size() == 1 && elseStatementBlock.getStatements().get(0) instanceof IfStatement) {
				elseStatementBlock.getStatements().get(0).accept(this);
			}
			else {
				ifStatement.getElseStatementBlock().accept(this);
			}
		}
	}

	@Override
	public void visit(ImpliesOperatorExpression impliesOperatorExpression) {
		unparseBinaryOperatorExpression(impliesOperatorExpression, "implies");
	}

	@Override
	public void visit(Import import_) {
		buffer.append("import \"" + import_.getPath() + "\";");
	}

	@Override
	public void visit(IntegerLiteral integerLiteral) {
		buffer.append(integerLiteral.getText());
	}

	@Override
	public void visit(ItemSelectorExpression itemSelectorExpression) {
		itemSelectorExpression.getTargetExpression().accept(this);
		buffer.append("[");
		itemSelectorExpression.getIndexExpression().accept(this);
		buffer.append("]");
	}

	@Override
	public void visit(LessEqualOperatorExpression lessEqualOperatorExpression) {
		unparseBinaryOperatorExpression(lessEqualOperatorExpression, "<=");
	}

	@Override
	public void visit(LessThanOperatorExpression lessThanOperatorExpression) {
		unparseBinaryOperatorExpression(lessThanOperatorExpression, "<");
	}

	@Override
	public void visit(MapLiteralExpression mapLiteralExpression) {
		buffer.append(mapLiteralExpression.getMapName()).append("{");
		Iterator> li = mapLiteralExpression.getKeyValueExpressionPairs().iterator();
		while (li.hasNext()) {
			Entry next = li.next();
			next.getKey().accept(this);
			buffer.append(" = ");
			next.getValue().accept(this);
			if (li.hasNext()) comma();
		}
		buffer.append("}");
	}

	@Override
	public void visit(MinusOperatorExpression minusOperatorExpression) {
		unparseBinaryOperatorExpression(minusOperatorExpression, "-");
	}

	@Override
	public void visit(ModelDeclaration modelDeclaration) {
		buffer.append("model ");
		modelDeclaration.getNameExpression().accept(this);
		if (!modelDeclaration.getAliasNameExpressions().isEmpty()) {
			buffer.append(" alias ");
			Iterator li = modelDeclaration.getAliasNameExpressions().iterator();
			while (li.hasNext()) {
				li.next().accept(this);
				if (li.hasNext()) comma();
			}
		}
		buffer.append(" driver ");
		modelDeclaration.getDriverNameExpression().accept(this);
		buffer.append(" {");
		Iterator li = modelDeclaration.getModelDeclarationParameters().iterator();
		while (li.hasNext()) {
			li.next().accept(this);
			if (li.hasNext()) comma();
		}
		buffer.append("}");
	}

	@Override
	public void visit(ModelDeclarationParameter modelDeclarationParameter) {
		buffer.append(modelDeclarationParameter.getKey());
		buffer.append(" = \"");
		buffer.append(modelDeclarationParameter.getValue());
		buffer.append("\"");
	}

	@Override
	public void visit(NameExpression nameExpression) {
		buffer.append(nameExpression.getName());
	}

	@Override
	public void visit(NegativeOperatorExpression negativeOperatorExpression) {
		buffer.append("-");
		unparse(negativeOperatorExpression.getFirstOperand());
	}

	@Override
	public void visit(NewInstanceExpression newInstanceExpression) {
		buffer.append("new ");
		newInstanceExpression.getTypeExpression().accept(this);
		if (!newInstanceExpression.getParameterExpressions().isEmpty()) {
			buffer.append("(");
			Iterator li = newInstanceExpression.getParameterExpressions().iterator();
			while (li.hasNext()) {
				li.next().accept(this);
				if (li.hasNext()) comma();
			}
			buffer.append(")");
		}
	}

	@Override
	public void visit(NotEqualsOperatorExpression notEqualsOperatorExpression) {
		unparseBinaryOperatorExpression(notEqualsOperatorExpression, notEqualsOperatorExpression.getOperator() != null ? notEqualsOperatorExpression.getOperator() : "<>");
	}

	@Override
	public void visit(NotOperatorExpression notOperatorExpression) {
		buffer.append("not ");
		notOperatorExpression.getFirstOperand().accept(this);
	}

	@Override
	public void visit(Operation operation) {
		unparseAnnotations(operation);
		buffer.append("operation ");
		if (operation.getContextTypeExpression() != null) {
			operation.getContextTypeExpression().accept(this);
			space();
		}
		buffer.append(operation.getName() + "(");
		Iterator li = operation.getFormalParameters().iterator();
		while (li.hasNext()) {
			li.next().accept(this);
			if (li.hasNext()) comma();
		}
		buffer.append(") ");
		if (operation.getReturnTypeExpression() != null) {
			buffer.append(": ");
			operation.getReturnTypeExpression().accept(this);
			space();
		}
		operation.getBody().accept(this);
	}

	@Override
	public void visit(OperationCallExpression operationCallExpression) {
		if (operationCallExpression.getTargetExpression() != null) {
			unparse(operationCallExpression.getTargetExpression());
			arrowOrDot(operationCallExpression);
		}
		buffer.append(operationCallExpression.getName() + "(");
		Iterator li = operationCallExpression.getParameterExpressions().iterator();
		while (li.hasNext()) {
			li.next().accept(this);
			if (li.hasNext()) comma();
		}
		buffer.append(")");
	}

	@Override
	public void visit(OrOperatorExpression orOperatorExpression) {
		unparseBinaryOperatorExpression(orOperatorExpression, "or");
	}

	@Override
	public void visit(Parameter parameter) {
		buffer.append(parameter.getName());
		if (parameter.getTypeExpression() != null) {
			buffer.append(" : ");
			parameter.getTypeExpression().accept(this);
		}
	}

	@Override
	public void visit(PlusOperatorExpression plusOperatorExpression) {
		unparseBinaryOperatorExpression(plusOperatorExpression, "+");
	}

	@Override
	public void visit(PostfixOperatorExpression postfixOperatorExpression) {
		postfixOperatorExpression.getFirstOperand().accept(this);
		buffer.append(postfixOperatorExpression.isIncrease() ? "++" : "--");
	}

	@Override
	public void visit(PropertyCallExpression propertyCallExpression) {
		propertyCallExpression.getTargetExpression().accept(this);
		// TODO: Check null-safe
		arrowOrDot(propertyCallExpression);
		propertyCallExpression.getNameExpression().accept(this);
	}

	@Override
	public void visit(RealLiteral realLiteral) {
		buffer.append(realLiteral.getText());
	}

	@Override
	public void visit(ReturnStatement returnStatement) {
		buffer.append("return");
		if (returnStatement.getReturnedExpression() != null) {
			buffer.append(" ");
			returnStatement.getReturnedExpression().accept(this);
		}
		semicolon();
	}

	@Override
	public void visit(AnnotationBlock annotationBlock) {
		annotationBlock.getAnnotations().forEach(a -> {indent(); a.accept(this); newline();});
	}
	
	@Override
	public void visit(SimpleAnnotation simpleAnnotation) {
		buffer.append("@" + simpleAnnotation.getName());
		if (simpleAnnotation.getValue() != null) {
			buffer.append(" " + simpleAnnotation.getValue());
		}
	}
	
	@Override
	public void visit(ExecutableAnnotation executableAnnotation) {
		buffer.append("$" + executableAnnotation.getName());
		if (executableAnnotation.getExpression() != null) {
			space();
			executableAnnotation.getExpression().accept(this);
		}
	}

	@Override
	public void visit(StatementBlock statementBlock) {
		if (module == null || statementBlock != module.getMain()) {
			buffer.append("{");
			newline();
			indentation++;
		}
		statementBlock.getStatements().forEach(s -> {indent(); s.accept(this); newline();});
		if (module == null || statementBlock != module.getMain()) {
			indentation--;
			indent();
			buffer.append("}");
		}
	}
	
	protected void indent() {
		for (int i=0;i { indent(); c.accept(this); newline();});
		if (switchStatement.getDefault() != null) {
			indent(); switchStatement.getDefault().accept(this); newline();
		}
		indentation--;
		indent();
		buffer.append("}");
		
	}

	@Override
	public void visit(TernaryExpression ternaryExpression) {
		ternaryExpression.getFirstOperand().accept(this);
		buffer.append(" ? ");
		ternaryExpression.getSecondOperand().accept(this);
		buffer.append(" : ");
		ternaryExpression.getThirdOperand().accept(this);
	}

	@Override
	public void visit(ThrowStatement throwStatement) {
		buffer.append("throw");
		if (throwStatement.getThrown() != null) {
			buffer.append(" ");
			throwStatement.getThrown().accept(this);
		}
		semicolon();
	}

	@Override
	public void visit(TimesOperatorExpression timesOperatorExpression) {
		unparseBinaryOperatorExpression(timesOperatorExpression, "*");
	}
	
	protected void unparseBinaryOperatorExpression(OperatorExpression operatorExpression, String operator) {
		operatorExpression.getFirstOperand().accept(this);
		buffer.append(" " + operator + " ");
		operatorExpression.getSecondOperand().accept(this);
	}
	
	protected void arrowOrDot(FeatureCallExpression expression) {
		if (expression.isNullSafe()) buffer.append("?");
		buffer.append(expression.isArrow() ? "->" : ".");
	}
	
	@Override
	public void visit(TransactionStatement transactionStatement) {
		buffer.append("transaction ");
		Iterator li = transactionStatement.getModelNames().iterator();
		while (li.hasNext()) {
			li.next().accept(this);
			if (li.hasNext()) comma();
			else space();
		}
		transactionStatement.getBody().accept(this);
	}

	@Override
	public void visit(TypeExpression typeExpression) {
		buffer.append(typeExpression.getName());
		if (typeExpression.getNativeType() != null) {
			buffer.append("(");
			typeExpression.getNativeType().accept(this);
			buffer.append(")");
		}
		else if (!typeExpression.getParameterTypeExpressions().isEmpty()) {
			buffer.append("(");
			Iterator li = typeExpression.getParameterTypeExpressions().iterator();
			while (li.hasNext()) {
				li.next().accept(this);
				if (li.hasNext()) comma();
			}
			buffer.append(")");
		}
	}

	@Override
	public void visit(VariableDeclaration variableDeclaration) {
		buffer.append("var " + variableDeclaration.getName());
		if (variableDeclaration.getTypeExpression() != null) {
			buffer.append(" : ");
			if (variableDeclaration.isInstantiate()) buffer.append("new ");
			variableDeclaration.getTypeExpression().accept(this);
		}
	}

	@Override
	public void visit(WhileStatement whileStatement) {
		buffer.append("while (");
		unparse(whileStatement.getConditionExpression());
		buffer.append(")");
		whileStatement.getBodyStatementBlock().accept(this);
	}

	@Override
	public void visit(XorOperatorExpression xorOperatorExpression) {
		unparseBinaryOperatorExpression(xorOperatorExpression, "xor");
	}
	
	protected void unparseAnnotations(AnnotatableModuleElement annotatableModuleElement) {
		if (annotatableModuleElement.getAnnotationBlock() != null) {
			annotatableModuleElement.getAnnotationBlock().accept(this);
		}
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy