/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.dsl.processor.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.lang.model.type.TypeMirror;
import com.oracle.truffle.dsl.processor.java.ElementUtils;
public class MethodSpec {
private final ParameterSpec returnType;
private final List<ParameterSpec> optional = new ArrayList<>();
private final List<ParameterSpec> required = new ArrayList<>();
private final List<ParameterSpec> annotations = new ArrayList<>();
private boolean ignoreAdditionalParameters;
private boolean ignoreAdditionalSpecifications;
private boolean variableRequiredParameters;
private List<TypeDef> typeDefinitions;
public MethodSpec(ParameterSpec returnType) {
this.returnType = returnType;
}
public void setVariableRequiredParameters(boolean variableRequiredParameters) {
this.variableRequiredParameters = variableRequiredParameters;
}
public boolean isVariableRequiredParameters() {
return variableRequiredParameters;
}
public void setIgnoreAdditionalParameters(boolean ignoreAdditionalParameter) {
this.ignoreAdditionalParameters = ignoreAdditionalParameter;
}
public boolean isIgnoreAdditionalParameters() {
return ignoreAdditionalParameters;
}
public void addOptional(ParameterSpec spec) {
optional.add(spec);
}
public ParameterSpec addRequired(ParameterSpec spec) {
required.add(spec);
return spec;
}
public List<ParameterSpec> getAnnotations() {
return annotations;
}
public ParameterSpec getReturnType() {
return returnType;
}
public List<ParameterSpec> getRequired() {
return required;
}
public List<ParameterSpec> getOptional() {
return optional;
}
public List<ParameterSpec> getAll() {
List<ParameterSpec> specs = new ArrayList<>();
specs.add(getReturnType());
specs.addAll(getOptional());
specs.addAll(getRequired());
return specs;
}
public void applyTypeDefinitions(String prefix) {
this.typeDefinitions = createTypeDefinitions(prefix);
}
private List<TypeDef> createTypeDefinitions(String prefix) {
List<TypeDef> typeDefs = new ArrayList<>();
int defIndex = 0;
for (ParameterSpec spec : getAll()) {
Collection<TypeMirror> allowedTypes = spec.getAllowedTypes();
Collection<TypeMirror> types = spec.getAllowedTypes();
if (types != null && allowedTypes.size() > 1) {
TypeDef foundDef = null;
for (TypeDef def : typeDefs) {
if (allowedTypes.equals(def.getTypes())) {
foundDef = def;
break;
}
}
if (foundDef == null) {
foundDef = new TypeDef(types, prefix + defIndex);
typeDefs.add(foundDef);
defIndex++;
}
spec.setTypeDefinition(foundDef);
}
}
return typeDefs;
}
public String toSignatureString(String methodName) {
StringBuilder b = new StringBuilder();
b.append(" ");
b.append(createTypeSignature(returnType, true));
b.append(" ");
b.append(methodName);
b.append("(");
String sep = "";
for (ParameterSpec optionalSpec : getOptional()) {
b.append(sep);
b.append("[");
b.append(createTypeSignature(optionalSpec, false));
b.append("]");
sep = ", ";
}
for (int i = 0; i < getRequired().size(); i++) {
ParameterSpec requiredSpec = getRequired().get(i);
b.append(sep);
if (isVariableRequiredParameters() && i == getRequired().size() - 1) {
b.append(("{"));
}
b.append(createTypeSignature(requiredSpec, false));
if (isVariableRequiredParameters() && i == getRequired().size() - 1) {
b.append(("}"));
}
sep = ", ";
}
b.append(")");
if (typeDefinitions != null && !typeDefinitions.isEmpty()) {
b.append("\n\n");
String lineSep = "";
for (TypeDef def : typeDefinitions) {
b.append(lineSep);
b.append(" <").append(def.getName()).append(">");
b.append(" = {");
String separator = "";
for (TypeMirror type : def.getTypes()) {
b.append(separator).append(ElementUtils.getSimpleName(type));
separator = ", ";
}
b.append("}");
lineSep = "\n";
}
}
return b.toString();
}
private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) {
StringBuilder builder = new StringBuilder();
TypeDef foundTypeDef = spec.getTypeDefinition();
if (foundTypeDef != null) {
builder.append("<" + foundTypeDef.getName() + ">");
} else if (spec.getAllowedTypes().size() >= 1) {
builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().iterator().next()));
} else {
builder.append("void");
}
if (!typeOnly) {
builder.append(" ");
builder.append(spec.getName());
}
return builder.toString();
}
@Override
public String toString() {
return toSignatureString("methodName");
}
static final class TypeDef {
private final Collection<TypeMirror> types;
private final String name;
private TypeDef(Collection<TypeMirror> types, String name) {
this.types = types;
this.name = name;
}
public Collection<TypeMirror> getTypes() {
return types;
}
public String getName() {
return name;
}
}
public void setIgnoreAdditionalSpecifications(boolean ignoreAdditoinalSpecifications) {
this.ignoreAdditionalSpecifications = ignoreAdditoinalSpecifications;
}
public boolean isIgnoreAdditionalSpecifications() {
return ignoreAdditionalSpecifications;
}
}