/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.option.processor;
import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.JavaFileObject;
import com.oracle.truffle.llvm.option.Constants;
import com.oracle.truffle.llvm.option.Option;
import com.oracle.truffle.llvm.option.OptionCategory;
public final class OptionsClassGenerator {
private final ProcessingEnvironment processingEnv;
private final TypeElement optionClassElement;
private final List<VariableElement> optionElements;
private final String packageName;
private final String clazzName;
private final Set<Consumer<Writer>> optionInitializer = new HashSet<>();
OptionsClassGenerator(ProcessingEnvironment processingEnv, TypeElement optionClassElement, List<VariableElement> optionElements) {
this.processingEnv = processingEnv;
this.optionClassElement = optionClassElement;
this.optionElements = optionElements;
this.clazzName = Utils.getSimpleSubClassName(optionClassElement);
this.packageName = Utils.getPackageName(optionClassElement);
}
public void generate() throws IOException {
JavaFileObject file = processingEnv.getFiler().createSourceFile(Utils.getFullOptionsClassName(optionClassElement), optionClassElement);
Writer w = file.openWriter();
w.append("package ").append(packageName).append(";\n");
appendImports(w);
w.append("public final class ").append(clazzName).append(" extends ").append(Utils.getSimpleName(optionClassElement)).append(" {\n");
appendStaticConstructor(w);
appendOptionFields(w);
appendConstructor(w);
appendFactoryMethod(w);
appendOptionGetters(w);
for (Consumer<Writer> initializer : optionInitializer) {
initializer.accept(w);
}
w.append("}\n");
w.close();
}
private void appendFactoryMethod(Writer w) throws IOException {
w.append(" public static ").append(clazzName).append(" create() {\n");
w.append(" return new ").append(clazzName).append("();\n");
w.append(" }\n");
}
private void appendStaticConstructor(Writer w) throws IOException {
w.append(" static {\n");
for (VariableElement e : optionElements) {
w.append(" OptionSummary.registerOption(\"").append(getCategory()).append("\", \"").append(getNameOfOption(e)).append("\", \"").append(getCommandLineOption(e)).append("\", ").append(
getDefaultValueAsString(e)).append(", \"").append(
getHelpOfOption(e)).append("\");\n");
}
w.append(" }\n");
}
private static String getDefaultValueAsString(VariableElement e) {
if (Utils.isStringArr(e.asType())) {
return "java.util.Arrays.toString(" + e.getSimpleName().toString() + ")";
} else {
return "String.valueOf(" + e.getSimpleName().toString() + ")";
}
}
private String getCategory() {
return optionClassElement.getAnnotation(OptionCategory.class).name();
}
private static String getNameOfOption(VariableElement optionElement) {
Option annotation = optionElement.getAnnotation(Option.class);
if (annotation.name().equals("")) {
return optionElement.getSimpleName().toString();
} else {
return annotation.name();
}
}
private static String getCommandLineOption(VariableElement optionElement) {
Option annotation = optionElement.getAnnotation(Option.class);
String commandLineOption = Constants.OPTION_PREFIX + annotation.commandLineName();
return commandLineOption;
}
private static String getHelpOfOption(VariableElement optionElement) {
Option annotation = optionElement.getAnnotation(Option.class);
return annotation.help();
}
private static void appendImports(Writer w) throws IOException {
w.append("import com.oracle.truffle.llvm.option.OptionSummary;\n");
}
private void appendOptionFields(Writer w) throws IOException {
for (VariableElement e : optionElements) {
w.append(" private final ").append(getTypeOptionName(e)).append(" ").append(getInternalOptionName(e)).append(";\n");
}
}
private void appendOptionGetters(Writer w) throws IOException {
for (VariableElement e : optionElements) {
w.append(" public ").append(getTypeOptionName(e)).append(" ").append(firstLetterLowerCase(getNameOfOption(e))).append("() {\n");
w.append(" return ").append(getInternalOptionName(e)).append(";\n");
w.append(" }\n");
}
}
private static String firstLetterLowerCase(String name) {
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
private void appendConstructor(Writer w) throws IOException {
w.append(" private ").append(clazzName).append("() {\n");
for (VariableElement e : optionElements) {
w.append(" ").append(getInternalOptionName(e)).append(" = ").append(optionInitializer(e)).append(";\n");
}
w.append(" }\n");
}
private static void appendGetBooleanOption(Writer w) throws IOException {
w.append(" private static boolean getBooleanOption(String option, boolean defaultValue) {\n");
w.append(" if (System.getProperty(option) == null) {\n");
w.append(" return defaultValue;\n");
w.append(" } else {\n");
w.append(" return Boolean.getBoolean(option);\n");
w.append(" }\n");
w.append(" }\n\n");
}
private static void appendGetIntegerOption(Writer w) throws IOException {
w.append(" private static int getIntegerOption(String option, int defaultValue) {\n");
w.append(" if (System.getProperty(option) == null) {\n");
w.append(" return defaultValue;\n");
w.append(" } else {\n");
w.append(" return Integer.getInteger(option);\n");
w.append(" }\n");
w.append(" }\n\n");
}
private static void appendGetStringOption(Writer w) throws IOException {
w.append(" private static String getStringOption(String option, String defaultValue) {\n");
w.append(" if (System.getProperty(option) == null) {\n");
w.append(" return defaultValue;\n");
w.append(" } else {\n");
w.append(" return System.getProperty(option);\n");
w.append(" }\n");
w.append(" }\n\n");
}
private static void appendGetStringArrOption(Writer w) throws IOException {
w.append(" private static String[] getStringArrOption(String option, String[] defaultValue) {\n");
w.append(" if (System.getProperty(option) == null) {\n");
w.append(" return defaultValue;\n");
w.append(" } else {\n");
w.append(" return System.getProperty(option).split(\"").append(Constants.OPTION_ARRAY_SEPARATOR).append("\");\n");
w.append(" }\n");
w.append(" }\n\n");
}
private static String getInternalOptionName(VariableElement option) {
return "internal_" + getNameOfOption(option);
}
private String getTypeOptionName(VariableElement option) {
if (Utils.isBoolean(processingEnv, option.asType())) {
return "boolean";
} else if (Utils.isInt(processingEnv, option.asType())) {
return "int";
} else if (Utils.isString(processingEnv, option.asType())) {
return "String";
} else if (Utils.isStringArr(option.asType())) {
return "String[]";
} else {
throw new AssertionError();
}
}
private String optionInitializer(VariableElement option) {
if (Utils.isBoolean(processingEnv, option.asType())) {
optionInitializer.add(t -> {
try {
appendGetBooleanOption(t);
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
return "getBooleanOption(\"" + getCommandLineOption(option) + "\", " + option.getSimpleName().toString() + ")";
} else if (Utils.isInt(processingEnv, option.asType())) {
optionInitializer.add(t -> {
try {
appendGetIntegerOption(t);
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
return "getIntegerOption(\"" + getCommandLineOption(option) + "\", " + option.getSimpleName().toString() + ")";
} else if (Utils.isString(processingEnv, option.asType())) {
optionInitializer.add(t -> {
try {
appendGetStringOption(t);
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
return "getStringOption(\"" + getCommandLineOption(option) + "\", " + option.getSimpleName().toString() + ")";
} else if (Utils.isStringArr(option.asType())) {
optionInitializer.add(t -> {
try {
appendGetStringArrOption(t);
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
return "getStringArrOption(\"" + getCommandLineOption(option) + "\", " + option.getSimpleName().toString() + ")";
} else {
throw new AssertionError();
}
}
}