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();
}
}