Skip to content

Commit

Permalink
[MOREL-210] Fold long types when printing
Browse files Browse the repository at this point in the history
  • Loading branch information
julianhyde committed Dec 13, 2023
1 parent 1b02c28 commit 5aa8b23
Show file tree
Hide file tree
Showing 2 changed files with 270 additions and 90 deletions.
164 changes: 142 additions & 22 deletions src/main/java/net/hydromatic/morel/compile/Pretty.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
import net.hydromatic.morel.ast.Op;
import net.hydromatic.morel.eval.Codes;
import net.hydromatic.morel.foreign.RelList;
import net.hydromatic.morel.parse.Parsers;
import net.hydromatic.morel.type.DataType;
import net.hydromatic.morel.type.FnType;
import net.hydromatic.morel.type.ForallType;
import net.hydromatic.morel.type.ListType;
import net.hydromatic.morel.type.PrimitiveType;
Expand All @@ -32,12 +32,12 @@
import net.hydromatic.morel.type.TypeSystem;
import net.hydromatic.morel.util.Ord;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

import java.util.List;
import javax.annotation.Nonnull;

import static net.hydromatic.morel.parse.Parsers.appendId;
import static net.hydromatic.morel.util.Pair.forEachIndexed;

import static java.util.Objects.requireNonNull;
Expand All @@ -64,17 +64,18 @@ class Pretty {
StringBuilder pretty(@Nonnull StringBuilder buf,
@Nonnull Type type, @Nonnull Object value) {
int lineEnd = lineWidth < 0 ? -1 : (buf.length() + lineWidth);
return pretty1(buf, 0, new int[] {lineEnd}, 0, type, value);
return pretty1(buf, 0, new int[] {lineEnd}, 0, type, value, 0, 0);
}

/** Prints a value to a buffer. If the first attempt goes beyond
* {@code lineEnd}, back-tracks, adds a newline and indent, and
* tries again one time. */
private StringBuilder pretty1(@Nonnull StringBuilder buf, int indent,
int[] lineEnd, int depth, @Nonnull Type type, @Nonnull Object value) {
int[] lineEnd, int depth, @Nonnull Type type, @Nonnull Object value,
int leftPrec, int rightPrec) {
final int start = buf.length();
final int end = lineEnd[0];
pretty2(buf, indent, lineEnd, depth, type, ImmutableList.of(), value);
pretty2(buf, indent, lineEnd, depth, type, value, leftPrec, rightPrec);
if (end >= 0 && buf.length() > end) {
// Reset to start, remove trailing whitespace, add newline
buf.setLength(start);
Expand All @@ -89,7 +90,7 @@ private StringBuilder pretty1(@Nonnull StringBuilder buf, int indent,

lineEnd[0] = lineWidth < 0 ? -1 : (buf.length() + lineWidth);
indent(buf, indent);
pretty2(buf, indent, lineEnd, depth, type, ImmutableList.of(), value);
pretty2(buf, indent, lineEnd, depth, type, value, leftPrec, rightPrec);
}
return buf;
}
Expand All @@ -101,29 +102,127 @@ private static void indent(@Nonnull StringBuilder buf, int indent) {
}

private StringBuilder pretty2(@Nonnull StringBuilder buf,
int indent, int[] lineEnd, int depth,
@Nonnull Type type, List<? extends Type> argTypes,
@Nonnull Object value) {
int indent, int[] lineEnd, int depth, @Nonnull Type type,
@Nonnull Object value, int leftPrec, int rightPrec) {
if (value instanceof TypedVal) {
final TypedVal typedVal = (TypedVal) value;
final StringBuilder buf2 = new StringBuilder("val ");
Parsers.appendId(buf2, typedVal.name)
appendId(buf2, typedVal.name)
.append(" = ");
pretty1(buf, indent, lineEnd, depth, PrimitiveType.BOOL,
buf2.toString());
pretty1(buf, indent + 2, lineEnd, depth + 1, typedVal.type, typedVal.o);
buf2.toString(), 0, 0);
pretty1(buf, indent + 2, lineEnd, depth + 1, typedVal.type, typedVal.o,
0, 0);
buf.append(' ');
pretty1(buf, indent + 2, lineEnd, depth, PrimitiveType.BOOL,
": " + unqualified(typedVal.type).moniker());
new TypeVal(": ", unqualified(typedVal.type)), 0, 0);
return buf;
}

if (value instanceof NamedVal) {
final NamedVal namedVal = (NamedVal) value;
Parsers.appendId(buf, namedVal.name)
appendId(buf, namedVal.name)
.append('=');
pretty1(buf, indent, lineEnd, depth, type, namedVal.o);
pretty1(buf, indent, lineEnd, depth, type, namedVal.o, 0, 0);
return buf;
}

if (value instanceof LabelVal) {
final LabelVal labelVal = (LabelVal) value;
final String prefix =
appendId(new StringBuilder(), labelVal.label)
.append(':')
.toString();
pretty1(buf, indent, lineEnd, depth, type,
new TypeVal(prefix, labelVal.type), 0, 0);
return buf;
}

if (value instanceof TypeVal) {
final TypeVal typeVal = (TypeVal) value;
final int start;
buf.append(typeVal.prefix);
int indent2 = indent + typeVal.prefix.length();
switch (typeVal.type.op()) {
case DATA_TYPE:
case ID:
case TY_VAR:
return pretty1(buf, indent2, lineEnd, depth, type,
typeVal.type.moniker(), 0, 0);

case LIST:
if (leftPrec > Op.LIST.left
|| rightPrec > Op.LIST.right) {
pretty1(buf, indent2, lineEnd, depth, type, "(", 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, typeVal, 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, ")", 0, 0);
return buf;
}
final ListType listType = (ListType) typeVal.type;
pretty1(buf, indent2, lineEnd, depth, type,
new TypeVal("", listType.elementType), leftPrec, Op.LIST.left);
return buf.append(" list");

case TUPLE_TYPE:
if (leftPrec > Op.TUPLE_TYPE.left
|| rightPrec > Op.TUPLE_TYPE.right) {
pretty1(buf, indent2, lineEnd, depth, type, "(", 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, typeVal, 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, ")", 0, 0);
return buf;
}
final TupleType tupleType = (TupleType) typeVal.type;
start = buf.length();
List<Type> argTypes = tupleType.argTypes;
for (int i = 0; i < argTypes.size(); i++) {
Type argType = argTypes.get(i);
if (buf.length() > start) {
pretty1(buf, indent2, lineEnd, depth, type,
" * ", 0, 0);
}
pretty1(buf, indent2, lineEnd, depth, type,
new TypeVal("", argType),
i == 0 ? leftPrec : Op.TUPLE_TYPE.right,
i == argTypes.size() - 1 ? rightPrec : Op.TUPLE_TYPE.left);
}
return buf;

case RECORD_TYPE:
final RecordType recordType = (RecordType) typeVal.type;
buf.append("{");
start = buf.length();
recordType.argNameTypes.forEach((name, elementType) -> {
if (buf.length() > start) {
buf.append(", ");
}
pretty1(buf, indent2 + 1, lineEnd, depth, type,
new LabelVal(name, elementType), 0, 0);
});
return buf.append("}");

case FUNCTION_TYPE:
if (leftPrec > Op.FUNCTION_TYPE.left
|| rightPrec > Op.FUNCTION_TYPE.right) {
pretty1(buf, indent2, lineEnd, depth, type, "(", 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, typeVal, 0, 0);
pretty1(buf, indent2, lineEnd, depth, type, ")", 0, 0);
return buf;
}
final FnType fnType = (FnType) typeVal.type;
pretty1(buf, indent2 + 1, lineEnd, depth, type,
new TypeVal("", fnType.paramType),
leftPrec, Op.FUNCTION_TYPE.left);
pretty1(buf, indent2 + 1, lineEnd, depth, type, " -> ", 0, 0);
pretty1(buf, indent2 + 1, lineEnd, depth, type,
new TypeVal("", fnType.resultType),
Op.FUNCTION_TYPE.right, rightPrec);
return buf;

default:
throw new AssertionError("unknown type " + typeVal.type);
}
}

if (printDepth >= 0 && depth > printDepth) {
buf.append('#');
return buf;
Expand Down Expand Up @@ -196,7 +295,7 @@ private StringBuilder pretty2(@Nonnull StringBuilder buf,
buf.append(",");
}
pretty1(buf, indent + 1, lineEnd, depth + 1, nameType.getValue(),
new NamedVal(nameType.getKey(), o));
new NamedVal(nameType.getKey(), o), 0, 0);
});
return buf.append("}");

Expand All @@ -210,13 +309,13 @@ private StringBuilder pretty2(@Nonnull StringBuilder buf,
if (buf.length() > start) {
buf.append(",");
}
pretty1(buf, indent + 1, lineEnd, depth + 1, elementType, o);
pretty1(buf, indent + 1, lineEnd, depth + 1, elementType, o, 0, 0);
});
return buf.append(")");

case FORALL_TYPE:
return pretty2(buf, indent, lineEnd, depth + 1, ((ForallType) type).type,
ImmutableList.of(), value);
value, 0, 0);

case DATA_TYPE:
final DataType dataType = (DataType) type;
Expand All @@ -239,8 +338,7 @@ private StringBuilder pretty2(@Nonnull StringBuilder buf,
if (needParentheses) {
buf.append('(');
}
pretty2(buf, indent, lineEnd, depth + 1, typeConArgType,
ImmutableList.of(), arg);
pretty2(buf, indent, lineEnd, depth + 1, typeConArgType, arg, 0, 0);
if (needParentheses) {
buf.append(')');
}
Expand Down Expand Up @@ -277,10 +375,10 @@ private StringBuilder printList(@Nonnull StringBuilder buf,
}
if (printLength >= 0 && o.i >= printLength) {
pretty1(buf, indent + 1, lineEnd, depth + 1, PrimitiveType.BOOL,
"...");
"...", 0, 0);
break;
} else {
pretty1(buf, indent + 1, lineEnd, depth + 1, elementType, o.e);
pretty1(buf, indent + 1, lineEnd, depth + 1, elementType, o.e, 0, 0);
}
}
return buf.append("]");
Expand Down Expand Up @@ -310,6 +408,28 @@ private static class NamedVal {
this.o = o;
}
}

/** Wrapper that indicates that a value should be printed "label:type". */
private static class LabelVal {
final String label;
final Type type;

LabelVal(String label, Type type) {
this.label = label;
this.type = type;
}
}

/** Wrapper around a type value. */
private static class TypeVal {
final String prefix;
final Type type;

TypeVal(String prefix, Type type) {
this.prefix = prefix;
this.type = type;
}
}
}

// End Pretty.java
Loading

0 comments on commit 5aa8b23

Please sign in to comment.