/*
* #%~
* VDM Code Generator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program 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, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.vdm2java;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.expressions.PExp;
import org.overture.ast.lex.Dialect;
import org.overture.codegen.ir.IRSettings;
import org.overture.codegen.ir.declarations.ADefaultClassDeclIR;
import org.overture.codegen.ir.declarations.AInterfaceDeclIR;
import org.overture.codegen.utils.GeneralCodeGenUtils;
import org.overture.codegen.utils.GeneralUtils;
import org.overture.codegen.utils.Generated;
import org.overture.codegen.utils.GeneratedModule;
import org.overture.config.Settings;
import org.overture.typechecker.util.TypeCheckerUtil.TypeCheckResult;
import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.FormatterException;
public class JavaCodeGenUtil
{
private static Logger log = Logger.getLogger(JavaCodeGenUtil.class.getName());
public static Generated generateJavaFromExp(String exp,
IRSettings irSettings, JavaSettings javaSettings, Dialect dialect)
throws AnalysisException
{
JavaCodeGen vdmCodeGen = new JavaCodeGen();
vdmCodeGen.setSettings(irSettings);
vdmCodeGen.setJavaSettings(javaSettings);
return generateJavaFromExp(exp, vdmCodeGen, dialect);
}
public static Generated generateJavaFromExp(String exp,
JavaCodeGen vdmCodeGen, Dialect dialect) throws AnalysisException
{
Settings.dialect = dialect;
TypeCheckResult<PExp> typeCheckResult = GeneralCodeGenUtils.validateExp(exp);
if (typeCheckResult.errors.size() > 0)
{
throw new AnalysisException("Unable to type check expression: "
+ exp);
}
try
{
return vdmCodeGen.generateJavaFromVdmExp(typeCheckResult.result);
} catch (AnalysisException
| org.overture.codegen.ir.analysis.AnalysisException e)
{
throw new AnalysisException("Unable to generate code from expression: "
+ exp + ". Exception message: " + e.getMessage());
}
}
public static String formatJavaCode(String code)
{
try
{
return new Formatter().formatSource(code);
} catch (FormatterException e)
{
log.error("Could not format code: " + e.getMessage());
e.printStackTrace();
return null;
}
}
public static boolean isQuote(org.overture.codegen.ir.INode decl,
JavaSettings settings)
{
if (decl instanceof ADefaultClassDeclIR)
{
ADefaultClassDeclIR clazz = (ADefaultClassDeclIR) decl;
if (clazz.getPackage() == null)
{
return false;
}
String javaPackage = settings.getJavaRootPackage();
if (javaPackage == null || javaPackage.equals(""))
{
return clazz.getPackage().equals(JavaCodeGen.JAVA_QUOTES_PACKAGE);
}
if (clazz.getPackage().equals(javaPackage + "."
+ JavaCodeGen.JAVA_QUOTES_PACKAGE))
{
return true;
}
}
return false;
}
public static boolean isValidJavaPackage(String pack)
{
if (pack == null)
{
return false;
}
pack = pack.trim();
Pattern pattern = Pattern.compile("^[a-zA-Z_\\$][\\w\\$]*(?:\\.[a-zA-Z_\\$][\\w\\$]*)*$");
if (!pattern.matcher(pack).matches())
{
return false;
}
String[] split = pack.split("\\.");
for (String s : split)
{
if (isJavaKeyword(s))
{
return false;
}
}
return true;
}
public static String getFolderFromJavaRootPackage(String pack)
{
if (!isValidJavaPackage(pack))
{
return null;
} else
{
return pack.replaceAll("\\.", "/");
}
}
public static boolean isJavaKeyword(String s)
{
if (s == null)
{
return false;
} else
{
s = s.trim();
if (s.isEmpty())
{
return false;
}
}
for (String kw : IJavaConstants.RESERVED_WORDS)
{
if (s.equals(kw))
{
return true;
}
}
return false;
}
/**
* Checks whether the given String is a valid Java identifier.
*
* @param s
* the String to check
* @return <code>true</code> if 's' is an identifier, <code>false</code> otherwise
*/
public static boolean isValidJavaIdentifier(String s)
{
if (s == null || s.length() == 0)
{
return false;
}
if (isJavaKeyword(s))
{
return false;
}
char[] c = s.toCharArray();
if (!Character.isJavaIdentifierStart(c[0]))
{
return false;
}
for (int i = 1; i < c.length; i++)
{
if (!Character.isJavaIdentifierPart(c[i]))
{
return false;
}
}
return true;
}
/**
* Computes the indices of characters that need to be replaced with valid characters in order to make 's' a valid
* Java identifier. Please note that this method assumes that 's' is NOT a keyword.
*
* @param s
* the identifier to compute correction indices for.
* @return the indices of the characters that need to be corrected in order to make the identifier a valid Java
* identifier
*/
public static List<Integer> computeJavaIdentifierCorrections(String s)
{
List<Integer> correctionIndices = new LinkedList<Integer>();
if (s == null || s.length() == 0)
{
return correctionIndices;
}
char[] c = s.toCharArray();
if (!Character.isJavaIdentifierStart(c[0]))
{
correctionIndices.add(0);
}
for (int i = 1; i < c.length; i++)
{
if (!Character.isJavaIdentifierPart(c[i]))
{
correctionIndices.add(i);
}
}
return correctionIndices;
}
public static String[] findJavaFilePathsRec(File srcCodeFolder)
{
List<File> files = GeneralUtils.getFilesRecursively(srcCodeFolder);
List<String> javaFilePaths = new LinkedList<String>();
for (File f : files)
{
if (f.getName().endsWith(IJavaConstants.JAVA_FILE_EXTENSION))
{
javaFilePaths.add(f.getAbsolutePath());
}
}
return javaFilePaths.toArray(new String[] {});
}
public static File getModuleOutputDir(File outputDir, JavaCodeGen vdmCodGen,
GeneratedModule generatedClass)
{
File moduleOutputDir = outputDir;
String javaPackage = vdmCodGen.getJavaSettings().getJavaRootPackage();
if (generatedClass.getIrNode() instanceof ADefaultClassDeclIR)
{
javaPackage = ((ADefaultClassDeclIR) generatedClass.getIrNode()).getPackage();
} else if (generatedClass.getIrNode() instanceof AInterfaceDeclIR)
{
javaPackage = ((AInterfaceDeclIR) generatedClass.getIrNode()).getPackage();
} else
{
log.error("Expected IR node of " + generatedClass.getName()
+ " to be a class or interface declaration at this point. Got: "
+ generatedClass.getIrNode());
return null;
}
if (JavaCodeGenUtil.isValidJavaPackage(javaPackage))
{
String packageFolderPath = JavaCodeGenUtil.getFolderFromJavaRootPackage(javaPackage);
moduleOutputDir = new File(outputDir, packageFolderPath);
}
return moduleOutputDir;
}
}