Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / generators / JavaSpecific.java
package generators;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import code.ast.*;
import code.ast.Expression;
import code.ast.Variable;
import models.algebra.*;
import models.algebra.Type;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.JsonType;
import models.dataConstraintModel.ListType;
import models.dataConstraintModel.MapType;
import models.dataConstraintModel.TupleType;

public class JavaSpecific implements ILanguageSpecific {
	public static final Type typeVoid = new Type("Void", new code.ast.SimpleType("void"));
	public static final code.ast.SimpleType typeObject = new code.ast.SimpleType("Object");
	public static final code.ast.SimpleType typeBoolean = new code.ast.SimpleType("Boolean");
	public static final code.ast.SimpleType typeInteger = new code.ast.SimpleType("Integer");
	public static final code.ast.SimpleType typeLong = new code.ast.SimpleType("Long");
	public static final code.ast.SimpleType typeFloat = new code.ast.SimpleType("Float");
	public static final code.ast.SimpleType typeDouble = new code.ast.SimpleType("Double");
	public static final code.ast.SimpleType typeString = new code.ast.SimpleType("String");
	public static final code.ast.SimpleType typeList = new code.ast.SimpleType("List");
	public static final code.ast.SimpleType typeArrayList = new code.ast.SimpleType("ArrayList");
	public static final code.ast.SimpleType typeMap = new code.ast.SimpleType("Map");
	public static final code.ast.SimpleType typeMapEntry = new code.ast.SimpleType("Map.Entry");
	public static final code.ast.SimpleType typeHashMap = new code.ast.SimpleType("HashMap");
	public static final code.ast.SimpleType typePair = new code.ast.SimpleType("Pair");
	public static final String self = "this";

	@Override
	public CompilationUnit newCompilationUnit(TypeDeclaration component) {
		CompilationUnit cu = new CompilationUnit(component);
		cu.addImport(new ImportDeclaration("java.util.*"));
		return cu;
	}

	@Override
	public TypeDeclaration newTypeDeclaration(String typeName) {
		return new TypeDeclaration(typeName);
	}
	
	@Override
	public VariableDeclaration newVariableDeclaration(Type type, String varName) {
		return new VariableDeclaration(type, varName);
	}

	@Override
	public MethodDeclaration newMethodDeclaration(String methodName, Type returnType) {
		if (returnType == null) {
			returnType = typeVoid;
		}
		return new MethodDeclaration(methodName, returnType);
	}

	@Override
	public MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List<VariableDeclaration> parameters) {
		if (returnType == null && !isConstructor) {
			returnType = typeVoid;
		}
		return new MethodDeclaration(methodName, isConstructor, returnType, parameters);
	}

	@Override
	public FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName) {
		return new FieldDeclaration(fieldType, fieldName);
	}

	@Override
	public FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer) {
		return new FieldDeclaration(fieldType, fieldName, fieldInitializer);
	}
	
	@Override
	public ListType newListType(Type compType) {
		return newListType(compType, DataConstraintModel.typeList);
	}

	@Override
	public ListType newListType(Type compType, Type parentListType) {
		List<code.ast.Type> typeArgs = new ArrayList<>();
		if (isValueType(compType)) {
			typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType());
		} else {
			typeArgs.add((code.ast.Type) compType.getInterfaceType());
		}
		return new ListType("List", new code.ast.ParameterizedType(typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, typeArgs), parentListType, compType);		
	}
	
	@Override
	public MapType newMapType(Type keyType, String valueTypeName) {
		return newMapType(keyType, valueTypeName, DataConstraintModel.typeMap);
	}

	@Override
	public MapType newMapType(Type keyType, String valueTypeName, Type parentMapType) {
		Type valueType = new Type(valueTypeName, new code.ast.SimpleType(valueTypeName));
		List<code.ast.Type> typeArgs = new ArrayList<>();
		typeArgs.add((code.ast.Type) keyType.getInterfaceType());
		typeArgs.add((code.ast.Type) valueType.getInterfaceType());
		return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType);
	}

	@Override
	public MapType newMapType(Type keyType, Type valueType) {
		return newMapType(keyType, valueType, DataConstraintModel.typeMap);
	}

	@Override
	public MapType newMapType(Type keyType, Type valueType, Type parentMapType) {
		List<code.ast.Type> typeArgs = new ArrayList<>();
		typeArgs.add((code.ast.Type) keyType.getInterfaceType());
		if (isValueType(valueType)) {
			typeArgs.add((code.ast.Type) getWrapperType(valueType).getInterfaceType());
		} else {
			typeArgs.add((code.ast.Type) valueType.getInterfaceType());
		}
		return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType);
	}
	
	@Override
	public TupleType newTupleType(List<Type> componentTypes) {
		return newTupleType(componentTypes, DataConstraintModel.typeTuple);
	}

	@Override
	public TupleType newTupleType(List<Type> componentTypes, Type parentTupleType) {
		code.ast.Type implType = new code.ast.SimpleType("AbstractMap.SimpleEntry");
		code.ast.Type interfaceType = typeMapEntry;
		if (componentTypes.size() >= 2) {
			Type compType = componentTypes.get(componentTypes.size() - 1);
			if (isValueType(compType)) {
				interfaceType = (code.ast.Type) getWrapperType(compType).getInterfaceType();
			} else {
				interfaceType = (code.ast.Type) compType.getInterfaceType();
			}
			for (int i = componentTypes.size() - 2; i >= 0; i--) {
				List<code.ast.Type> typeArgs = new ArrayList<>();
				compType = componentTypes.get(i);
				if (isValueType(compType)) {
					typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType());
				} else {
					typeArgs.add((code.ast.Type) compType.getInterfaceType());
				}
				typeArgs.add(interfaceType);
				interfaceType = new code.ast.ParameterizedType(typeMapEntry, typeArgs);
			}
		}
		return new TupleType("Tuple", implType, interfaceType, parentTupleType, componentTypes);
	}
	
	@Override
	public JsonType newJsonType() {
		return new JsonType("Json", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(typeMap, List.of(typeString, typeObject)));
	}

	@Override
	public JsonType newJsonType(Type parentJsonType) {
		JsonType jsonType = newJsonType();
		jsonType.addParentType(parentJsonType);
		return jsonType;
	}

	@Override
	public boolean declareField() {
		return true;
	}
	
	@Override
	public String getSelfExp() {
		return self;
	}
	
	@Override
	public String getFieldAccessor(String fieldName) {
		return self + "." + fieldName;
	}
	
	@Override
	public String getMethodInvocation(String methodName) {
		return self + "." + methodName + "()";
	}

	@Override
	public String getMethodInvocation(String methodName, List<String> parameters) {
		if (parameters == null) return getMethodInvocation( methodName);
		String invocation = self + "." + methodName + "(";
		if (parameters.size() > 0) {
			for (int i = 0; i < parameters.size(); i++) {
				if (i < parameters.size() - 1) {
					invocation += parameters.get(i) + ", ";
				} else {
					invocation += parameters.get(i);
				}
			}
		}
		invocation += ")";
		return invocation;
	}

	@Override
	public String getMethodInvocation(String receiverName, String methodName) {
		return receiverName + "." + methodName + "()";
	}

	@Override
	public String getMethodInvocation(String receiverName, String methodName, List<String> parameters) {
		if (parameters == null) return getMethodInvocation(receiverName, methodName);
		String invocation = receiverName + "." + methodName + "(";
		if (parameters.size() > 0) {
			for (int i = 0; i < parameters.size(); i++) {
				if (i < parameters.size() - 1) {
					invocation += parameters.get(i) + ", ";
				} else {
					invocation += parameters.get(i);
				}
			}
		}
		invocation += ")";
		return invocation;
	}

	@Override
	public String getConstructorInvocation(String componentName, List<String> parameters) {
		String invocation = "new " + componentName + "(";
		if (parameters != null && parameters.size() > 0) {
			for (int i = 0; i < parameters.size(); i++) {
				if (i < parameters.size() - 1) {
					invocation += parameters.get(i) + ", ";
				} else {
					invocation += parameters.get(i);
				}
			}
		}
		invocation += ")";
		return invocation;
	}

	@Override
	public ReturnStatement getReturnStatement(String returnValue) {
		ReturnStatement returnStatement = new ReturnStatement();
		returnStatement.setExpression(new code.ast.Variable(returnValue) {
		});
		return returnStatement;
	}

	@Override
	public IfStatement getIfStatement(Term condition, Statement block) {
		IfStatement ifStatement = new IfStatement();
		String conditionSource = condition.toImplementation(new String[]{""});
		ifStatement.setExpression(new code.ast.Variable(conditionSource));
		ifStatement.setThenStatement(block);
		return ifStatement;
	}

	@Override
	public ForStatement getForStatementForList(String varName, String list) {
		VariableDeclaration varDec = new VariableDeclaration(DataConstraintModel.typeInt, varName, new code.ast.Constant("0"));
		VariableDeclarationStatement varDecStmt = new VariableDeclarationStatement();
		varDecStmt.addFragment(varDec);
		ForStatement forStatement = new ForStatement();
		forStatement.getInitializers().add(varDecStmt);
		InfixExpression condition = new InfixExpression(
				new Symbol("<", 2, Symbol.Type.INFIX),
				new code.ast.Variable(varName),
				new code.ast.Variable(list + ".size()")
		);
		forStatement.setExpression(condition);
		PostfixExpression increment = new PostfixExpression(
				new code.ast.Variable(varName),
				PostfixExpression.Operator.INCREMENT
		);
		forStatement.setUpdaters(Arrays.asList(new ExpressionStatement(increment)));
		return forStatement;
	}

	@Override
	public EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection) {
		EnhancedForStatement enhancedForStatement = new EnhancedForStatement();

		enhancedForStatement.setParameter(varDeclaration);
		enhancedForStatement.setExpression(new code.ast.Variable(collection));

		return enhancedForStatement;
	}

	@Override
	public EnhancedForStatement getForStatementForMap(String varName, String map) {
		VariableDeclaration varDeclaration = new VariableDeclaration(DataConstraintModel.typeString, varName);
		EnhancedForStatement enhancedForStatement = new EnhancedForStatement();
		
		enhancedForStatement.setParameter(varDeclaration);
		enhancedForStatement.setExpression(new code.ast.Variable(map + ".keySet()"));

		return enhancedForStatement;
	}

	@Override
	public String toComponentName(String name) {
		return name.substring(0, 1).toUpperCase() + name.substring(1);
	}

	@Override
	public String toVariableName(String name) {
		return name.substring(0, 1).toLowerCase() + name.substring(1);
	}

	@Override
	public String getMainComponentName() {
		return "Main";
	}

	@Override
	public String getAssignment() {
		return " = ";
	}

	@Override
	public String getStatementDelimiter() {
		return ";";
	}

	@Override
	public String getStringDelimiter() {
		return "\"";
	}

	@Override
	public String getOpeningScoreDelimiter() {
		return "{";
	}

	@Override
	public String getClosingScoreDelimiter() {
		return "}";
	}
	
	@Override
	public String getValueToStringExp(String typeName, String valueExp) {
		if (typeName.equals("int")) {
			return "Integer.toString(" + valueExp + ")";
		} else if (typeName.equals("float")) {
			return "Float.toString(" + valueExp + ")";
		} else if (typeName.equals("double")) {
			return "Double.toString(" + valueExp + ")";
		} else if (typeName.equals("boolean")) {
			return "Boolean.toString(" + valueExp + ")";
		} else {			
			return valueExp + ".toString()";
		}
	}

	@Override
	public String getStringToValueExp(String typeName, String strExp) {
		if (typeName.equals("int")) {
			return "Integer.parseInt(" + strExp + ")";
		} else if (typeName.equals("float")) {
			return "Float.parseFloat(" + strExp + ")";
		} else if (typeName.equals("double")) {
			return "Double.parseDouble(" + strExp + ")";
		} else if (typeName.equals("boolean")) {
			return "Boolean.parseBoolean(" + strExp + ")";
		} else if (typeName.startsWith("ArrayList") || typeName.startsWith("List")) {
			return "Arrays.asList(" + strExp + ".replace(\"[\",\"\").replace(\"]\",\"\").split(\",\",0))";
		} else {
			return strExp;
		}
	}

	@Override
	public String getPairExp(String first, String second) {
		return getConstructorInvocation(DataConstraintModel.typeTuple.getImplementationTypeName() + "<>", List.of(first, second));
	}

	@Override
	public String getFirstEntryFromMapExp(String map) {
		return getMethodInvocation(map, "entrySet().iterator().next");
	}

	@Override
	public String getTupleGet(String tupleExp, int idx, int length) {
		models.algebra.Expression t = new models.algebra.Variable(tupleExp);
		for (int i = 0; i < idx; i++) {
			Term next = new Term(DataConstraintModel.snd);
			next.addChild(t);
			t = next;
		}
		if (idx < length - 1) {
			Term last = new Term(DataConstraintModel.fst);
			last.addChild(t);
			t = last;
		}
		return t.toImplementation(new String[]{""});
	}

	@Override
	public String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List<VariableDeclaration> vars) {
		String statements = "";
		statements += newVariableDeclaration(tupleVar.getType(), tupleVar.getName())
							+ getAssignment() + tupleExp + getStatementDelimiter();
		for (int i = 0; i < vars.size(); i++) {
			VariableDeclaration var = vars.get(i);
			statements += "\n" + newVariableDeclaration(var.getType(), var.getName())
							+ getAssignment()
							+ getTupleGet(tupleVar.getName(), i, vars.size())
							+ getStatementDelimiter();
		}
		return statements;
	}

	@Override
	public boolean isValueType(Type type) {
		if (type == DataConstraintModel.typeInt 
				|| type == DataConstraintModel.typeLong
				|| type == DataConstraintModel.typeFloat
				|| type == DataConstraintModel.typeDouble
				|| type == DataConstraintModel.typeBoolean) {
			return true;
		}
		return false;
	}

	
	@Override
	public boolean isVoidType(Type type) {
		if (type == typeVoid) {
			return true;
		}
		return false;
	}

	@Override
	public Type getWrapperType(Type type) {
		if (type == DataConstraintModel.typeInt) {
			return new Type("Integer", typeInteger);
		} else if (type == DataConstraintModel.typeLong) {
			return new Type("Long", typeLong);
		} else if (type == DataConstraintModel.typeFloat) {
			return new Type("Float", typeFloat);
		} else if (type == DataConstraintModel.typeDouble) {
			return new Type("Double", typeDouble);
		} else if (type == DataConstraintModel.typeBoolean) {
			return new Type("Boolean", typeBoolean);
		}
		return type;
	}
	
	private String getImplementationTypeName(Type type) {
		if (type == null)
			return "Object";
		String wrapperType = DataConstraintModel.getWrapperType(type);
		if (wrapperType != null)
			return wrapperType;
		return type.getImplementationTypeName();
	}

	private String getInterfaceTypeName(Type type) {
		if (type == null)
			return "Object";
		String wrapperType = DataConstraintModel.getWrapperType(type);
		if (wrapperType != null)
			return wrapperType;
		return type.getInterfaceTypeName();
	}
}