/*
* Copyright 2010 Pablo Arrighi, Alex Concha, Miguel Lezama for version 1.
* Copyright 2013 Pablo Arrighi, Miguel Lezama, Kevin Mazet for version 2.
*
* This file is part of GOOL.
*
* GOOL is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, version 3.
*
* GOOL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License version 3 for more details.
*
* You should have received a copy of the GNU General Public License along with GOOL,
* in the file COPYING.txt. If not, see <http://www.gnu.org/licenses/>.
*/
package gool.generator.java;
import gool.ast.core.BinaryOperation;
import gool.ast.core.Catch;
import gool.ast.core.ClassDef;
import gool.ast.core.ClassNew;
import gool.ast.core.Constant;
import gool.ast.core.Constructor;
import gool.ast.core.CustomDependency;
import gool.ast.core.Dependency;
import gool.ast.core.EnhancedForLoop;
import gool.ast.core.EqualsCall;
import gool.ast.core.Field;
import gool.ast.core.Finally;
import gool.ast.core.MainMeth;
import gool.ast.core.Meth;
import gool.ast.core.Modifier;
import gool.ast.core.Operator;
import gool.ast.core.ParentCall;
import gool.ast.core.RecognizedDependency;
import gool.ast.core.Throw;
import gool.ast.core.ToStringCall;
import gool.ast.core.Try;
import gool.ast.core.TypeDependency;
import gool.ast.list.ListAddCall;
import gool.ast.list.ListContainsCall;
import gool.ast.list.ListGetCall;
import gool.ast.list.ListGetIteratorCall;
import gool.ast.list.ListIsEmptyCall;
import gool.ast.list.ListRemoveAtCall;
import gool.ast.list.ListRemoveCall;
import gool.ast.list.ListSizeCall;
import gool.ast.map.MapContainsKeyCall;
import gool.ast.map.MapEntryGetKeyCall;
import gool.ast.map.MapEntryGetValueCall;
import gool.ast.map.MapGetCall;
import gool.ast.map.MapGetIteratorCall;
import gool.ast.map.MapIsEmptyCall;
import gool.ast.map.MapPutCall;
import gool.ast.map.MapRemoveCall;
import gool.ast.map.MapSizeCall;
import gool.ast.system.SystemCommandDependency;
import gool.ast.system.SystemOutDependency;
import gool.ast.system.SystemOutPrintCall;
import gool.ast.type.IType;
import gool.ast.type.TypeBool;
import gool.ast.type.TypeChar;
import gool.ast.type.TypeDecimal;
import gool.ast.type.TypeEntry;
import gool.ast.type.TypeException;
import gool.ast.type.TypeInt;
import gool.ast.type.TypeList;
import gool.ast.type.TypeMap;
import gool.ast.type.TypeObject;
import gool.ast.type.TypeString;
import gool.generator.GeneratorHelper;
import gool.generator.common.CodeGeneratorNoVelocity;
import gool.generator.common.CommonCodeGenerator;
import gool.generator.common.GeneratorMatcher;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
public class JavaGenerator extends CommonCodeGenerator /*
* implements
* CodeGeneratorNoVelocity
*/{
private static Map<String, Dependency> customDependencies = new HashMap<String, Dependency>();
private static Logger logger = Logger.getLogger(JavaGenerator.class
.getName());
public void addCustomDependency(String key, Dependency value) {
customDependencies.put(key, value);
}
@Override
public String getCode(BinaryOperation binaryOp) {
if (!(binaryOp.getLeft() instanceof Constant)
&& binaryOp.getOperator() == Operator.EQUAL) {
return String.format("%s.equals(%s)", binaryOp.getLeft(),
binaryOp.getRight());
} else {
return super.getCode(binaryOp);
}
}
public String getCode(ClassNew classNew) {
return String.format("new %s(%s)", classNew.getType(),
StringUtils.join(classNew.getParameters(), ", "));
}
public String getCode(CustomDependency customDependency) {
if (!customDependencies.containsKey(customDependency.getName())) {
logger.info(String.format("Custom dependencies: %s, Desired: %s",
customDependencies, customDependency.getName()));
throw new IllegalArgumentException(
String.format(
"There is no equivalent type in Java for the GOOL type '%s'.",
customDependency.getName()));
}
return customDependencies.get(customDependency.getName()).toString();
}
@Override
public String getCode(EnhancedForLoop enhancedForLoop) {
return formatIndented(
"for (%s : %s){%1}",
enhancedForLoop.getVarDec(),
(enhancedForLoop.getExpression().getType() instanceof TypeMap) ? String
.format("%s.entrySet()",
enhancedForLoop.getExpression())
: enhancedForLoop.getExpression(),
enhancedForLoop.getStatements());
}
@Override
public String getCode(EqualsCall equalsCall) {
return String.format("%s.equals(%s)", equalsCall.getTarget(),
StringUtils.join(equalsCall.getParameters(), ", "));
}
public String getCode(ListAddCall lac) {
return String.format("%s.add(%s)", lac.getExpression(),
StringUtils.join(lac.getParameters(), ", "));
}
public String getCode(ListContainsCall lcc) {
return String.format("%s.contains(%s)", lcc.getExpression(),
StringUtils.join(lcc.getParameters(), ", "));
}
public String getCode(ListGetCall lgc) {
return String.format("%s.get(%s)", lgc.getExpression(),
StringUtils.join(lgc.getParameters(), ", "));
}
public String getCode(ListGetIteratorCall lgic) {
return String.format("%s.getIterator()", lgic.getExpression());
}
public String getCode(ListIsEmptyCall liec) {
return String.format("%s.isEmpty()", liec.getExpression());
}
public String getCode(ListRemoveAtCall lrc) {
return String.format("%s.remove(%s)", lrc.getExpression(),
StringUtils.join(lrc.getParameters(), ", "));
}
public String getCode(ListRemoveCall lrc) {
return String.format("%s.remove(%s)", lrc.getExpression(),
StringUtils.join(lrc.getParameters(), ", "));
}
public String getCode(ListSizeCall lsc) {
return String.format("%s.size()", lsc.getExpression());
}
public String getCode(MainMeth mainMeth) {
return "public static void main(String[] args)";
}
@Override
public String getCode(MapContainsKeyCall mapContainsKeyCall) {
return String.format("%s.containsKey(%s)",
mapContainsKeyCall.getExpression(),
StringUtils.join(mapContainsKeyCall.getParameters(), ", "));
}
@Override
public String getCode(MapEntryGetKeyCall mapEntryGetKeyCall) {
return String.format("%s.getKey()", mapEntryGetKeyCall.getExpression());
}
@Override
public String getCode(MapEntryGetValueCall mapEntryGetKeyCall) {
return String.format("%s.getValue()",
mapEntryGetKeyCall.getExpression());
}
@Override
public String getCode(MapGetCall mapGetCall) {
return String.format("%s.get(%s)", mapGetCall.getExpression(),
StringUtils.join(mapGetCall.getParameters(), ", "));
}
@Override
public String getCode(MapGetIteratorCall mapGetIteratorCall) {
return String.format("%s.getIterator()",
mapGetIteratorCall.getExpression());
}
@Override
public String getCode(MapIsEmptyCall mapIsEmptyCall) {
return String.format("%s.isEmpty()", mapIsEmptyCall.getExpression());
}
@Override
public String getCode(MapPutCall mapPutCall) {
return String.format("%s.put(%s)", mapPutCall.getExpression(),
StringUtils.join(mapPutCall.getParameters(), ", "));
}
@Override
public String getCode(MapRemoveCall mapRemoveCall) {
return String.format("%s.remove(%s)", mapRemoveCall.getExpression(),
StringUtils.join(mapRemoveCall.getParameters(), ", "));
}
@Override
public String getCode(MapSizeCall mapSizeCall) {
return String.format("%s.size()", mapSizeCall.getExpression());
}
@Override
public String getCode(ParentCall parentCall) {
String out = "super(";
if (parentCall.getParameters() != null) {
out += StringUtils.join(parentCall.getParameters(), ", ");
}
out += ")";
return out;
}
public String getCode(SystemOutDependency systemOutDependency) {
return "noprint";
}
@Override
public String getCode(SystemOutPrintCall systemOutPrintCall) {
return String.format("System.out.println(%s)",
StringUtils.join(systemOutPrintCall.getParameters(), ","));
}
public String getCode(ToStringCall tsc) {
return String.format("%s.toString()", tsc.getTarget());
}
@Override
public String getCode(TypeBool typeBool) {
return "Boolean";
}
@Override
public String getCode(TypeDecimal typeReal) {
return "Double";
}
@Override
public String getCode(TypeChar typeChar) {
return "char";
}
public String getCode(TypeDependency typeDependency) {
if (typeDependency.getType() instanceof TypeList) {
return "java.util.ArrayList";
}
if (typeDependency.getType() instanceof TypeMap) {
return "java.util.HashMap";
}
if (typeDependency.getType() instanceof TypeEntry) {
return "java.util.Map";
}
return super.getCode(typeDependency);
}
@Override
public String getCode(TypeEntry typeEntry) {
return String.format("Map.Entry<%s, %s>", typeEntry.getKeyType(),
typeEntry.getElementType());
}
@Override
public String getCode(TypeInt typeInt) {
return "Integer";
}
@Override
public String getCode(TypeList typeList) {
IType elementType = typeList.getElementType();
if (elementType == null) {
elementType = TypeObject.INSTANCE;
}
return String.format("ArrayList<%s>", elementType);
}
@Override
public String getCode(TypeMap typeMap) {
return String.format("HashMap<%s, %s>", typeMap.getKeyType(),
typeMap.getElementType());
}
@Override
public String getCode(TypeObject typeObject) {
return "Object";
}
@Override
public String getCode(TypeString typeString) {
return "String";
}
@Override
public String getCode(Modifier modifier) {
if (modifier == Modifier.OVERRIDE) {
return "";
}
if (modifier == Modifier.VIRTUAL) {
return "";
}
return modifier.name().toLowerCase();
}
@Override
public String getCode(SystemCommandDependency systemCommandDependency) {
// TODO Auto-generated method stub
return null;
}
// @Override
public String printClass(ClassDef classDef) {
StringBuilder sb = new StringBuilder(String.format(
"// Platform: %s\n\n", classDef.getPlatform()));
// print the package containing the class
if (classDef.getPpackage() != null)
sb = sb.append(String.format("package %s;\n\n",
classDef.getPackageName()));
// print the includes
Set<String> dependencies = GeneratorHelper.printDependencies(classDef);
if (!dependencies.isEmpty()) {
for (String dependency : dependencies) {
if (dependency != "noprint" && dependency.contains("."))
sb = sb.append(String.format("import %s;\n", dependency));
}
sb = sb.append("\n");
}
// print the class prototype
sb = sb.append(String.format("%s %s %s",
StringUtils.join(classDef.getModifiers(), ' '),
classDef.isInterface() ? "interface" : "class",
classDef.getName()));
if (classDef.getParentClass() != null)
sb = sb.append(String.format(" extends %s",
classDef.getParentClass()));
if (!classDef.getInterfaces().isEmpty())
sb = sb.append(String.format(" interfaces %s",
StringUtils.join(classDef.getInterfaces(), ", ")));
sb = sb.append(" {\n\n");
// print the fields
for (Field field : classDef.getFields())
sb = sb.append(formatIndented("%-1%s;\n\n", field));
// print the methods
for (Meth meth : classDef.getMethods()) {
if (classDef.isInterface()) {
sb = sb.append(formatIndented("%-1%s;\n\n", meth.getHeader()));
} else {
if (meth.isConstructor()) {
sb = sb.append(formatIndented("%-1%s {\n%-2%s;%2%-1}\n\n",
meth.getHeader(), ((Constructor) meth)
.getInitCalls().get(0), meth.getBlock()));
} else {
sb = sb.append(formatIndented("%-1%s {%2%-1}\n\n",
meth.getHeader(), meth.getBlock()));
}
}
}
return sb.toString() + "}";
}
@Override
public String getCode(Throw throwStatement) {
return String.format("throw %s", throwStatement.getExpression());
}
@Override
public String getCode(Catch catchStatement) {
return formatIndented("catch (%s %s) {%1}", catchStatement
.getParameter().getType(), catchStatement.getParameter()
.getName(), catchStatement.getBlock());
}
@Override
public String getCode(Try tryStatement) {
String ret = formatIndented("try {%1}", tryStatement.getBlock());
for (Catch c : tryStatement.getCatches()) {
ret += " " + c;
}
if (!tryStatement.getFinilyBlock().getStatements().isEmpty())
ret += formatIndented(" finally {%1}",
tryStatement.getFinilyBlock());
return ret;
}
@Override
public String getCode(TypeException typeException) {
switch (typeException.getKind()) {
case GLOBAL:
return "Exception";
case ARITHMETIC:
return "ArithmeticException";
case COLLECTION:
return "ArrayStoreException";
case CAST:
return "ClassCastException";
case ENUM:
return "EnumConstantNotPresentException";
case ARGUMENT:
return "IllegalArgumentException";
case THREAD:
return "IllegalMonitorStateException";
case STATE:
return "IllegalStateException";
case ARRAY:
return "IndexOutOfBoundsException";
case ARRAYSIZE:
return "NegativeArraySizeException";
case NULLREFERENCE:
return "NullPointerException";
case SECURITY:
return "SecurityException";
case TYPE:
return "TypeNotPresentException";
case UNSUPORTED:
return "UnsupportedOperationException";
case CLASSNOTFOUND:
return "ClassNotFoundException";
case DEFAULT:
return "CloneNotSupportedException";
case ACCESS:
return "IllegalAccessException";
case NEWINSTANCE:
return "InstantiationException";
case INTERUPT:
return "InterruptedException";
case NOSUCHFIELD:
return "NoSuchFieldException";
case NOSUCHMETH:
return "NoSuchMethodException";
default:
return typeException.getName();
}
}
public String getCode(RecognizedDependency recognizedDependency) {
List<String> imports = GeneratorMatcher.matchImports(recognizedDependency.getName());
if(imports.isEmpty())
return "/* import "+recognizedDependency.getName()+" not generated by GOOL, passed on. */";
String result = "";
for (String Import : imports) {
if (Import.startsWith("+"))
Import = Import.substring(1);
result += "import " + Import + ";\n";
}
return result;
}
}