/* * 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.android; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import gool.ast.core.BinaryOperation; import gool.ast.core.Block; import gool.ast.core.Catch; import gool.ast.core.ClassNew; import gool.ast.core.Constant; import gool.ast.core.CustomDependency; import gool.ast.core.Dependency; import gool.ast.core.EnhancedForLoop; import gool.ast.core.EqualsCall; import gool.ast.core.Expression; 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.Statement; 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.common.CommonCodeGenerator; import gool.generator.common.GeneratorMatcher; public class AndroidGenerator extends CommonCodeGenerator { private static Map<String, Dependency> customDependencies = new HashMap<String, Dependency>(); 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==(%s)", binaryOp.getLeft(), binaryOp.getRight()); } else { return super.getCode(binaryOp); } } public String getCode(ClassNew classNew) { if (classNew.getType().toString().equals("File")) return String.format( "new %s (Environment.getExternalStorageDirectory(),%s)", classNew.getType(), StringUtils.join(classNew.getParameters(), ", ")); if (classNew.getType().toString().equals("FileReader")) { List<String> tempList = new ArrayList<String>(); for (Expression expression : classNew.getParameters()) { if (expression.getType() instanceof TypeString) { String tempString = "new File (Environment.getExternalStorageDirectory()," + expression.toString() + ")"; tempList.add(String.valueOf(tempString)); } else { tempList.add(expression.toString()); } } return String.format("new %s (%s)", classNew.getType(), StringUtils.join(tempList, ",")); } if (classNew.getType().toString().equals("FileWriter")) { List<String> tempList2 = new ArrayList<String>(); for (Expression expression : classNew.getParameters()) { if (expression.getType() instanceof TypeString) { String tempString = "new File (Environment.getExternalStorageDirectory()," + expression.toString() + ")"; tempList2.add(String.valueOf(tempString)); } else { tempList2.add(expression.toString()); } } return String.format("new %s (%s)", classNew.getType(), StringUtils.join(tempList2, ",")); } return String.format("new %s(%s)", classNew.getType(), StringUtils.join(classNew.getParameters(), ", ")); } public String getCode(CustomDependency customDependency) { if (!customDependencies.containsKey(customDependency.getName())) { System.out.println(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 String .format("for(%s : %s){%s}", 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()); } /** * Changed from java, might cause problems if input java has more than one * main method or if Android uses public static void main. Currently * sufficient for preliminary tests on HelloWorld. */ public String getCode(MainMeth mainMeth) { return "public static void EntryMethod(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"; } // TODO Currently an android.widget.TextView called systemOutTextBox is used // as a System.out equivalent, this can probably be optimized with a // Singleton // type instance @Override public String getCode(SystemOutPrintCall systemOutPrintCall) { return String.format( "PrintOut.getSystemOutTextBox().append(%s+\"\\n\"); ", StringUtils.join(systemOutPrintCall.getParameters(), ",")) + String.format(" Log.i(\"JUnitSysOut\",String.valueOf(%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"; } 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(TypeChar typeChar) { return "char"; } @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 getCode(Try t) { StringBuilder result = new StringBuilder(); result.append("try{\n"); for (Statement statement : t.getBlock().getStatements()) { result.append(statement); if (!(statement instanceof Block)) { result.append(";").append("\n"); } } result.append("\n}"); // closing bracket for (Catch c : t.getCatches()) { result.append(getCode(c)); } return result.toString(); } @Override public String getCode(Catch c) { StringBuilder result = new StringBuilder(); result.append("\n catch("); result.append(") {\n"); for (Statement statement : c.getBlock().getStatements()) { result.append(statement); if (!(statement instanceof Block)) { result.append(";").append("\n"); } } result.append("\n}"); return result.toString(); } @Override public String getCode(Meth meth) { if (meth.getThrowStatement().size() == 0) { return super.getCode(meth); } else { return String.format("%s %s %s(%s) throws %s", getCode(meth.getModifiers()), meth.getType(), meth.getName(), StringUtils.join(meth.getParams(), ", "), StringUtils.join(meth.getThrowStatement(), ", ")); } } @Override public String getCode(Throw throwStatement) { // TODO Auto-generated method stub return null; } @Override public String getCode(TypeException typeException) { // TODO Auto-generated method stub return null; } public String getCode(RecognizedDependency recognizedDependency) { String result = ""; for (String Import : GeneratorMatcher.matchImports(recognizedDependency .getName())) { if (Import.startsWith("+")) Import = Import.substring(1); result += "import " + Import + ";\n"; } return result; } }