blob: f88a55d7a03950216bab7da452c5b8a9e445dc35 [file] [log] [blame]
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.JsonReaderEx;
import org.jetbrains.jsonProtocol.ItemDescriptor;
import org.jetbrains.jsonProtocol.ProtocolMetaModel;
import java.util.ArrayList;
import java.util.List;
class OutputClassScope extends ClassScope {
OutputClassScope(DomainGenerator generator, NamePath classNamePath) {
super(generator, classNamePath);
}
<P extends ItemDescriptor.Named> void generate(TextOutput out, List<P> parameters) {
if (parameters == null) {
return;
}
List<P> mandatoryParameters = new ArrayList<>();
List<P> optionalParameters = new ArrayList<>();
for (P parameter : parameters) {
if (parameter.optional()) {
optionalParameters.add(parameter);
}
else {
mandatoryParameters.add(parameter);
}
}
if (!mandatoryParameters.isEmpty()) {
generateConstructor(out, mandatoryParameters, null);
if (mandatoryParameters.size() == 1) {
P parameter = mandatoryParameters.get(0);
TypeDescriptor typeData = new OutputMemberScope(getName(parameter)).resolveType(parameter);
if (typeData.getType().getFullText().equals("int[]")) {
BoxableType[] types = new BoxableType[mandatoryParameters.size()];
types[0] = new ListType(BoxableType.INT) {
@Override
String getShortText(NamePath contextNamespace) {
return getFullText();
}
@Override
String getFullText() {
return "gnu.trove.TIntArrayList";
}
@Override
String getWriteMethodName() {
return "writeIntList";
}
};
out.newLine().newLine();
generateConstructor(out, mandatoryParameters, types);
types[0] = new ListType(BoxableType.INT) {
@Override
String getShortText(NamePath contextNamespace) {
return getFullText();
}
@Override
String getFullText() {
return "int";
}
@Override
String getWriteMethodName() {
return "writeSingletonIntArray";
}
};
out.newLine().newLine();
generateConstructor(out, mandatoryParameters, types);
}
}
}
// generate enum classes after constructor
for (P parameter : parameters) {
if (parameter.getEnum() != null) {
out.newLine().newLine();
appendEnumClass(out, parameter.description(), parameter.getEnum(), Generator.capitalizeFirstChar((parameter.name())));
}
}
for (P parameter : optionalParameters) {
out.newLine().newLine();
if (parameter.description() != null) {
out.append("/**").newLine().append(" * @param v ").append(parameter.description()).newLine().append(" */").newLine();
}
CharSequence type = new OutputMemberScope(parameter.name()).resolveType(parameter).getType().getShortText(getClassContextNamespace());
if (type.equals(JsonReaderEx.class.getCanonicalName())) {
type = "String";
}
out.append("public ").append(getShortClassName());
out.space().append(parameter.name()).append("(").append(type);
out.space().append("v").append(")").openBlock();
appendWriteValueInvocation(out, parameter, "v", null);
out.newLine().append("return this;");
out.closeBlock();
}
}
private <P extends ItemDescriptor.Named> void generateConstructor(@NotNull TextOutput out, @NotNull List<P> mandatoryParameters, @Nullable BoxableType[] mandatoryParameterTypes) {
boolean hasDoc = false;
for (P parameter : mandatoryParameters) {
if (parameter.description() != null) {
hasDoc = true;
break;
}
}
if (hasDoc) {
out.append("/**").newLine();
for (P parameter : mandatoryParameters) {
if (parameter.description() != null) {
out.append(" * @param " + parameter.name() + ' ' + parameter.description()).newLine();
}
}
out.append(" */").newLine();
}
out.append("public " + getShortClassName() + '(');
if (mandatoryParameterTypes == null) {
mandatoryParameterTypes = new BoxableType[mandatoryParameters.size()];
}
for (int i = 0, length = mandatoryParameterTypes.length; i < length; i++) {
assert mandatoryParameterTypes != null;
if (mandatoryParameterTypes[i] == null) {
P parameter = mandatoryParameters.get(i);
mandatoryParameterTypes[i] = new OutputMemberScope(parameter.name()).resolveType(parameter).getType();
}
}
boolean needComa = false;
for (int i = 0, size = mandatoryParameters.size(); i < size; i++) {
P parameter = mandatoryParameters.get(i);
if (needComa) {
out.comma();
}
assert mandatoryParameterTypes != null;
out.append(mandatoryParameterTypes[i].getShortText(getClassContextNamespace()));
out.space().append(parameter.name());
needComa = true;
}
out.append(")").openBlock(false);
for (int i = 0, size = mandatoryParameters.size(); i < size; i++) {
P parameter = mandatoryParameters.get(i);
out.newLine();
assert mandatoryParameterTypes != null;
appendWriteValueInvocation(out, parameter, parameter.name(), mandatoryParameterTypes[i]);
}
out.closeBlock();
}
private void appendWriteValueInvocation(TextOutput out, ItemDescriptor.Named parameter, String valueRefName, @Nullable BoxableType type) {
if (type == null) {
type = new OutputMemberScope(parameter.name()).resolveType(parameter).getType();
}
boolean blockOpened = false;
if (parameter.optional()) {
String nullValue;
if (parameter.name().equals("columnNumber") || parameter.name().equals("column")) {
// todo generic solution
nullValue = "-1";
}
else {
nullValue = null;
}
if (nullValue != null) {
blockOpened = true;
out.append("if (v != ").append(nullValue).append(")").openBlock();
}
else if (parameter.name().equals("enabled")) {
blockOpened = true;
out.append("if (!v)").openBlock();
}
else if (parameter.name().equals("ignoreCount")) {
blockOpened = true;
out.append("if (v > 0)").openBlock();
}
}
// todo CallArgument (we should allow write null as value)
out.append(parameter.name().equals("value") && type.getWriteMethodName().equals("writeString") ? "writeNullableString" : type.getWriteMethodName()).append("(");
out.quote(parameter.name()).comma().append(valueRefName).append(");");
if (blockOpened) {
out.closeBlock();
}
}
@Override
protected TypeData.Direction getTypeDirection() {
return TypeData.Direction.OUTPUT;
}
class OutputMemberScope extends MemberScope {
protected OutputMemberScope(String memberName) {
super(OutputClassScope.this, memberName);
}
@Override
public BoxableType generateEnum(final String description, final List<String> enumConstants) {
return new StandaloneType(new NamePath(Generator.capitalizeFirstChar(getMemberName()), getClassContextNamespace()), "writeEnum");
}
@Override
public BoxableType generateNestedObject(String description, List<ProtocolMetaModel.ObjectProperty> propertyList) {
throw new UnsupportedOperationException();
}
}
private static void appendEnumClass(TextOutput out, String description, List<String> enumConstants, String enumName) {
out.doc(description);
Enums.appendEnums(enumConstants, enumName, false, out);
out.newLine().append("private final String protocolValue;").newLine();
out.newLine().append(enumName).append("(String protocolValue)").openBlock();
out.append("this.protocolValue = protocolValue;").closeBlock();
out.newLine().newLine().append("public String toString()").openBlock();
out.append("return protocolValue;").closeBlock();
out.closeBlock();
}
}