aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar vladmos <vladmos@google.com>2017-06-30 14:01:45 +0200
committerGravatar Marcel Hlopko <hlopko@google.com>2017-07-03 09:04:59 +0200
commit469079377a9561a7c2cc7a46492c44e012b9fb33 (patch)
tree7b9baaf83c2a9ee2c9a57862d833ae72d5ae9305 /src
parent86c9d942452d82a479d499ffe61695a983f16bba (diff)
Refactor Printer
It's now easier to customize Printer if in different situations objects should be printed differently. Also its API is cleaner now. Names of methods of SkylarkValue objects now reflect names of Skylark functions: SkylarkValue#repr and SkylarkPrintableValue#str. PiperOrigin-RevId: 160635154
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/Artifact.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/cmdline/Label.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/BuildType.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/FilesetEntry.java34
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java21
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/output/OutputFormatter.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintableValue.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrinter.java83
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Environment.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FormatParser.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java24
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/GlobList.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java46
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Printer.java965
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Runtime.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SliceExpression.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Type.java15
-rw-r--r--src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java6
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java4
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java6
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java40
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/PrinterTest.java38
39 files changed, 848 insertions, 664 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
index 574fa6a6cf..39f435cdb6 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
@@ -31,8 +31,8 @@ import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
@@ -366,8 +366,8 @@ public abstract class AbstractAction implements Action, SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, prettyPrint()); // TODO(bazel-team): implement a readable representation
+ public void repr(SkylarkPrinter printer) {
+ printer.append(prettyPrint()); // TODO(bazel-team): implement a readable representation
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 05d66df2d4..2416ed6d3b 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -32,10 +32,10 @@ import com.google.devtools.build.lib.shell.ShellUtils;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.EvalUtils.ComparisonException;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.Path;
@@ -877,7 +877,7 @@ public class Artifact
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, toString()); // TODO(bazel-team): implement a readable representation
+ public void repr(SkylarkPrinter printer) {
+ printer.append(toString()); // TODO(bazel-team): implement a readable representation
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
index 33c5d0aab2..7a36d4db27 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
@@ -33,8 +33,8 @@ import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -152,12 +152,12 @@ public final class Runfiles {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "SymlinkEntry(path = ");
- Printer.write(buffer, getPath().toString(), quotationMark);
- Printer.append(buffer, ", artifact = ");
- getArtifact().write(buffer, quotationMark);
- Printer.append(buffer, ")");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("SymlinkEntry(path = ");
+ printer.repr(getPath().toString());
+ printer.append(", artifact = ");
+ getArtifact().repr(printer);
+ printer.append(")");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
index b689f6daa7..9c229018b0 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
@@ -24,13 +24,13 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintableValue;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.util.StringCanonicalizer;
import com.google.devtools.build.lib.util.StringUtilities;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
-import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
@@ -562,34 +562,12 @@ public final class Label implements Comparable<Label>, Serializable, SkylarkPrin
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- // We don't use the Skylark Printer class here to avoid creating a circular dependency.
- //
- // TODO(bazel-team): make the representation readable Label(//foo),
- // and isolate the legacy functions that want the unreadable variant.
- try {
- // There is no need to escape the contents of the Label since characters that might otherwise
- // require escaping are disallowed.
- buffer.append(quotationMark);
- buffer.append(toString());
- buffer.append(quotationMark);
- } catch (IOException e) {
- // This function will only be used with in-memory Appendables, hence we should never get here.
- throw new AssertionError(e);
- }
+ public void repr(SkylarkPrinter printer) {
+ printer.repr(getCanonicalForm());
}
@Override
- public void print(Appendable buffer, char quotationMark) {
- // We don't use the Skylark Printer class here to avoid creating a circular dependency.
- //
- // TODO(bazel-team): make the representation readable Label(//foo),
- // and isolate the legacy functions that want the unreadable variant.
- try {
- buffer.append(toString());
- } catch (IOException e) {
- // This function will only be used with in-memory Appendables, hence we should never get here.
- throw new AssertionError(e);
- }
+ public void str(SkylarkPrinter printer) {
+ printer.append(getCanonicalForm());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
index a602515b45..e0b1bbcf8c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
@@ -25,6 +25,7 @@ import com.google.devtools.build.lib.packages.License.DistributionType;
import com.google.devtools.build.lib.packages.License.LicenseParsingException;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SelectorValue;
import com.google.devtools.build.lib.syntax.Type;
@@ -293,10 +294,10 @@ public final class BuildType {
convertedFrom.computeIfAbsent(label, k -> new ArrayList<Object>());
convertedFrom.get(label).add(original);
}
- StringBuilder errorMessage = new StringBuilder();
+ BasePrinter errorMessage = Printer.getPrinter();
errorMessage.append("duplicate labels");
if (what != null) {
- errorMessage.append(" in ").append(what);
+ errorMessage.append(" in ").append(what.toString());
}
errorMessage.append(':');
boolean isFirstEntry = true;
@@ -310,9 +311,9 @@ public final class BuildType {
errorMessage.append(',');
}
errorMessage.append(' ');
- errorMessage.append(entry.getKey());
+ errorMessage.str(entry.getKey());
errorMessage.append(" (as ");
- Printer.write(errorMessage, entry.getValue());
+ errorMessage.repr(entry.getValue());
errorMessage.append(')');
}
throw new ConversionException(errorMessage.toString());
diff --git a/src/main/java/com/google/devtools/build/lib/packages/FilesetEntry.java b/src/main/java/com/google/devtools/build/lib/packages/FilesetEntry.java
index d52db41ad3..59eac45836 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/FilesetEntry.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/FilesetEntry.java
@@ -22,17 +22,15 @@ import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
-
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-
import javax.annotation.Nullable;
/**
@@ -74,22 +72,20 @@ public final class FilesetEntry implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "FilesetEntry(srcdir = ");
- Printer.write(buffer, getSrcLabel().toString(), quotationMark);
- Printer.append(buffer, ", files = ");
- Printer.write(buffer, makeStringList(getFiles()), quotationMark);
- Printer.append(buffer, ", excludes = ");
- Printer.write(buffer, makeList(getExcludes()), quotationMark);
- Printer.append(buffer, ", destdir = ");
- Printer.write(buffer, getDestDir().getPathString(), quotationMark);
- Printer.append(buffer, ", strip_prefix = ");
- Printer.write(buffer, getStripPrefix(), quotationMark);
- Printer.append(buffer, ", symlinks = ");
- Printer.append(buffer, quotationMark);
- Printer.append(buffer, getSymlinkBehavior().toString());
- Printer.append(buffer, quotationMark);
- Printer.append(buffer, ")");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("FilesetEntry(srcdir = ");
+ printer.repr(getSrcLabel().toString());
+ printer.append(", files = ");
+ printer.repr(makeStringList(getFiles()));
+ printer.append(", excludes = ");
+ printer.repr(makeList(getExcludes()));
+ printer.append(", destdir = ");
+ printer.repr(getDestDir().getPathString());
+ printer.append(", strip_prefix = ");
+ printer.repr(getStripPrefix());
+ printer.append(", symlinks = ");
+ printer.repr(getSymlinkBehavior().toString());
+ printer.append(")");
}
/** SymlinkBehavior decides what to do when a source file of a FilesetEntry is a symlink. */
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
index 26fcd30fc5..3a544c79a2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
@@ -20,9 +20,9 @@ import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.Environment;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Preconditions;
import java.util.Arrays;
@@ -96,9 +96,9 @@ public class SkylarkAspect implements SkylarkExportable {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "Aspect:");
- implementation.write(buffer, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.append("Aspect:");
+ implementation.repr(printer);
}
public String getName() {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java
index 1b67b13175..963b30eee6 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java
@@ -24,6 +24,7 @@ import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.NativeClassObjectConstructor.StructConstructor;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.Concatable;
@@ -231,25 +232,25 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable
}
/**
- * Convert the object to string using Skylark syntax. The output tries to be
- * reversible (but there is no guarantee, it depends on the actual values).
+ * Convert the object to string using Skylark syntax. The output tries to be reversible (but there
+ * is no guarantee, it depends on the actual values).
*/
@Override
- public void write(Appendable buffer, char quotationMark) {
+ public void repr(SkylarkPrinter printer) {
boolean first = true;
- Printer.append(buffer, constructor.getPrintableName());
- Printer.append(buffer, "(");
+ printer.append(constructor.getPrintableName());
+ printer.append("(");
// Sort by key to ensure deterministic output.
for (String key : Ordering.natural().sortedCopy(values.keySet())) {
if (!first) {
- Printer.append(buffer, ", ");
+ printer.append(", ");
}
first = false;
- Printer.append(buffer, key);
- Printer.append(buffer, " = ");
- Printer.write(buffer, values.get(key), quotationMark);
+ printer.append(key);
+ printer.append(" = ");
+ printer.repr(values.get(key));
}
- Printer.append(buffer, ")");
+ printer.append(")");
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/OutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/output/OutputFormatter.java
index 75f0b807ac..29cfb47c57 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/output/OutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/output/OutputFormatter.java
@@ -504,10 +504,7 @@ public abstract class OutputFormatter implements Serializable {
} else if (value instanceof TriState) {
value = ((TriState) value).toInt();
}
- // It is *much* faster to write to a StringBuilder compared to the PrintStream object.
- StringBuilder builder = new StringBuilder();
- Printer.write(builder, value);
- return builder.toString();
+ return Printer.repr(value);
}
/**
@@ -531,7 +528,6 @@ public abstract class OutputFormatter implements Serializable {
return String.join(" + ", selectors);
}
-
@Override
public void processOutput(Iterable<Target> partialResult) throws InterruptedException {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java
index 985c5f80b3..f3f012d45d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java
@@ -28,9 +28,9 @@ import com.google.devtools.build.lib.skylarkinterface.ParamType;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
@@ -232,9 +232,9 @@ public class SkylarkActionFactory implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "actions for");
- context.write(buffer, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.append("actions for");
+ context.repr(printer);
}
void nullify() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index 89f35200ac..5c1a50e957 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -60,10 +60,10 @@ import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -576,9 +576,9 @@ public final class SkylarkRuleContext implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "rule_collection:");
- skylarkRuleContext.write(buffer, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.append("rule_collection:");
+ skylarkRuleContext.repr(printer);
}
}
@@ -596,8 +596,8 @@ public final class SkylarkRuleContext implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, ruleLabelCanonicalName);
+ public void repr(SkylarkPrinter printer) {
+ printer.append(ruleLabelCanonicalName);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 9566dd3dc0..18c26d5a2f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -58,8 +58,8 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.ProguardHelper;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
-import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileType;
import java.util.List;
@@ -278,8 +278,8 @@ public final class AndroidRuleClasses {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "android_common.multi_cpu_configuration");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("android_common.multi_cpu_configuration");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
index 5b9ddb780e..79d595baf7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
@@ -57,7 +57,7 @@ public class ConfigFeatureFlag implements RuleConfiguredTargetFactory {
ruleContext.attributeError(
"allowed_values",
"cannot contain duplicates, but contained multiple of "
- + Printer.repr(duplicates.build(), '\''));
+ + Printer.repr(duplicates.build()));
}
String defaultValue = ruleContext.attributes().get("default_value", STRING);
@@ -65,9 +65,9 @@ public class ConfigFeatureFlag implements RuleConfiguredTargetFactory {
ruleContext.attributeError(
"default_value",
"must be one of "
- + Printer.repr(values.asList(), '\'')
+ + Printer.repr(values.asList())
+ ", but was "
- + Printer.repr(defaultValue, '\''));
+ + Printer.repr(defaultValue));
}
if (ruleContext.hasErrors()) {
@@ -86,9 +86,9 @@ public class ConfigFeatureFlag implements RuleConfiguredTargetFactory {
// TODO(mstaib): When configurationError is available, use that instead.
ruleContext.ruleError(
"value must be one of "
- + Printer.repr(values.asList(), '\'')
+ + Printer.repr(values.asList())
+ ", but was "
- + Printer.repr(value, '\''));
+ + Printer.repr(value));
return null;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintableValue.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintableValue.java
index 24353cebe6..69426ea6c8 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintableValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintableValue.java
@@ -14,14 +14,13 @@
package com.google.devtools.build.lib.skylarkinterface;
/**
- * A Skylark value that is represented by {@code print()} differently than by {@code write()}.
+ * A Skylark value that is represented by {@code str()} differently than by {@code repr()}.
*/
public interface SkylarkPrintableValue extends SkylarkValue {
/**
* Print an informal, human-readable representation of the value.
*
- * @param buffer the buffer to append the representation to
- * @param quotationMark The quote style (" or ') to be used
+ * @param printer a printer to be used for formatting nested values.
*/
- void print(Appendable buffer, char quotationMark);
+ void str(SkylarkPrinter printer);
}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrinter.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrinter.java
new file mode 100644
index 0000000000..0e950e4c62
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrinter.java
@@ -0,0 +1,83 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface;
+
+import java.util.List;
+import javax.annotation.Nullable;
+
+/**
+ * An interface for Printer.BasePrinter
+ *
+ * <p>Allows passing Printer.BasePrinter instances to classes that can't import Printer directly
+ * because of circular dependencies.
+ */
+public interface SkylarkPrinter {
+ /** Append a char to the printer's buffer */
+ SkylarkPrinter append(char c);
+
+ /** Append a char sequence to the printer's buffer */
+ SkylarkPrinter append(CharSequence s);
+
+ /**
+ * Prints a list to the printer's buffer. All list items are rendered with {@code repr}.
+ *
+ * @param list the list
+ * @param isTuple if true, uses parentheses, otherwise, uses square brackets. Also one-element
+ * tuples are rendered with a comma after the element.
+ * @return SkylarkPrinter
+ */
+ SkylarkPrinter printList(Iterable<?> list, boolean isTuple);
+
+ /**
+ * Prints a list to the printer's buffer. All list items are rendered with {@code repr}.
+ *
+ * @param list the list of objects to repr (each as with repr)
+ * @param before a string to print before the list items, e.g. an opening bracket
+ * @param separator a separator to print between items
+ * @param after a string to print after the list items, e.g. a closing bracket
+ * @param singletonTerminator null or a string to print after the list if it is a singleton.
+ * The singleton case is notably relied upon in python syntax to distinguish a tuple of size
+ * one such as ("foo",) from a merely parenthesized object such as ("foo")
+ * @return SkylarkPrinter
+ */
+ SkylarkPrinter printList(
+ Iterable<?> list, String before, String separator, String after,
+ @Nullable String singletonTerminator);
+
+ /**
+ * Renders an object with {@code repr} and append to the printer's buffer.
+ */
+ SkylarkPrinter repr(Object o);
+
+ /**
+ * Performs Python-style string formatting, as per {@code pattern % tuple}.
+ * Limitations: only {@code %d %s %r %%} are supported.
+ *
+ * @param pattern a format string
+ * @param arguments an array containing positional arguments
+ * @return SkylarkPrinter
+ */
+ SkylarkPrinter format(String pattern, Object... arguments);
+
+ /**
+ * Performs Python-style string formatting, as per {@code pattern % tuple}.
+ * Limitations: only {@code %d %s %r %%} are supported.
+ *
+ * @param pattern a format string
+ * @param arguments a list containing positional arguments
+ * @return SkylarkPrinter
+ */
+ SkylarkPrinter formatWithList(String pattern, List<?> arguments);
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
index bf72821c86..a7c8c2779b 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
@@ -17,7 +17,7 @@ package com.google.devtools.build.lib.skylarkinterface;
/**
* Java objects that are also Skylark values.
*
- * <p>This is used for extending the Skylark interpreted with domain-specific values.
+ * <p>This is used for extending the Skylark interpreter with domain-specific values.
*/
public interface SkylarkValue {
@@ -34,8 +34,7 @@ public interface SkylarkValue {
*
* <p>For regular data structures, the value should be parsable back into an equal data structure.
*
- * @param buffer the buffer to append the representation to
- * @param quotationMark The quote style (" or ') to be used
+ * @param printer a printer to be used for formatting nested values.
*/
- void write(Appendable buffer, char quotationMark);
+ void repr(SkylarkPrinter printer);
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
index c67f658261..b410ed8d4d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
@@ -567,7 +568,7 @@ public abstract class BaseFunction implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "<function " + getName() + ">");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("<function " + getName() + ">");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
index ba868188dd..fdb7f54bb7 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
@@ -20,7 +20,6 @@ import com.google.devtools.build.lib.syntax.Concatable.Concatter;
import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
import java.io.IOException;
-import java.util.Collections;
import java.util.IllegalFormatException;
/**
@@ -336,7 +335,8 @@ public final class BinaryOperatorExpression extends Expression {
}
/** Implements Operator.PERCENT. */
- private static Object percent(Object lval, Object rval, Location location) throws EvalException {
+ private static Object percent(Object lval, Object rval, Location location)
+ throws EvalException {
// int % int
if (lval instanceof Integer && rval instanceof Integer) {
if (rval.equals(0)) {
@@ -359,9 +359,9 @@ public final class BinaryOperatorExpression extends Expression {
String pattern = (String) lval;
try {
if (rval instanceof Tuple) {
- return Printer.formatToString(pattern, (Tuple) rval);
+ return Printer.formatWithList(pattern, (Tuple) rval);
}
- return Printer.formatToString(pattern, Collections.singletonList(rval));
+ return Printer.format(pattern, rval);
} catch (IllegalFormatException e) {
throw new EvalException(location, e.getMessage());
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index 45abea50d2..1a8d2b3cd6 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -698,8 +698,8 @@ public final class Environment implements Freezable {
// End users don't have access to setupDynamic, and it is an implementation error
// if we encounter a mutability exception.
throw new AssertionError(
- Printer.format(
- "Trying to bind dynamic variable '%s' in frozen environment %r", varname, this),
+ String.format(
+ "Trying to bind dynamic variable '%s' in frozen environment %s", varname, this),
e);
}
return this;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FormatParser.java b/src/main/java/com/google/devtools/build/lib/syntax/FormatParser.java
index 64ad8900ca..d4a2323994 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FormatParser.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FormatParser.java
@@ -15,6 +15,7 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
import java.util.List;
import java.util.Map;
@@ -90,9 +91,10 @@ public final class FormatParser {
History history,
StringBuilder output)
throws EvalException {
+ BasePrinter printer = Printer.getPrinter(output);
if (has(chars, pos + 1, '{')) {
// Escaped brace -> output and move to char after right brace
- output.append("{");
+ printer.append("{");
return 1;
}
@@ -119,7 +121,7 @@ public final class FormatParser {
}
// Format object for output
- output.append(Printer.str(value));
+ printer.str(value);
// Advances the current position to the index of the closing brace of the
// replacement field. Due to the definition of the enclosing for() loop,
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
index 63120932a0..682b15f629 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
@@ -28,6 +28,7 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause;
+import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
import com.google.devtools.build.lib.syntax.Runtime.NoneType;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
@@ -269,15 +270,15 @@ public final class FuncallExpression extends Expression {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
+ BasePrinter printer = Printer.getPrinter();
if (obj != null) {
- sb.append(obj).append(".");
+ printer.append(obj.toString()).append(".");
}
- sb.append(func);
- Printer.printList(sb, args, "(", ", ", ")", /* singletonTerminator */ null,
+ printer.append(func.toString());
+ printer.printAbbreviatedList(args, "(", ", ", ")", null,
Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT,
Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH);
- return sb.toString();
+ return printer.toString();
}
/**
@@ -326,7 +327,8 @@ public final class FuncallExpression extends Expression {
loc,
"method invocation returned None, please file a bug report: "
+ methodName
- + Printer.listString(ImmutableList.copyOf(args), "(", ", ", ")", null));
+ + Printer.printAbbreviatedList(
+ ImmutableList.copyOf(args), "(", ", ", ")", null));
}
}
// TODO(bazel-team): get rid of this, by having everyone use the Skylark data structures
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java b/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
index 9b0fb008ab..8517a3e38d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
@@ -19,6 +19,7 @@ import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Interner;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
+import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.util.StringCanonicalizer;
@@ -393,6 +394,7 @@ public abstract class FunctionSignature implements Serializable {
final boolean skipFirstMandatory) {
FunctionSignature signature = getSignature();
Shape shape = signature.getShape();
+ final BasePrinter printer = Printer.getPrinter(sb);
final ImmutableList<String> names = signature.getNames();
@Nullable final List<V> defaultValues = getDefaultValues();
@Nullable final List<T> types = getTypes();
@@ -418,7 +420,7 @@ public abstract class FunctionSignature implements Serializable {
public void comma() {
if (isMore) {
- sb.append(", ");
+ printer.append(", ");
}
isMore = true;
}
@@ -436,26 +438,26 @@ public abstract class FunctionSignature implements Serializable {
} else {
// We only append colons when there is a name.
if (showNames) {
- sb.append(": ");
+ printer.append(": ");
}
- sb.append(typeString);
+ printer.append(typeString);
}
}
public void mandatory(int i) {
comma();
if (showNames) {
- sb.append(names.get(i));
+ printer.append(names.get(i));
}
type(i);
}
public void optional(int i) {
mandatory(i);
if (showDefaults) {
- sb.append(" = ");
+ printer.append(" = ");
if (defaultValues == null) {
- sb.append("?");
+ printer.append("?");
} else {
- Printer.write(sb, defaultValues.get(j++));
+ printer.repr(defaultValues.get(j++));
}
}
}
@@ -472,9 +474,9 @@ public abstract class FunctionSignature implements Serializable {
}
if (hasStar) {
show.comma();
- sb.append("*");
+ printer.append("*");
if (starArg && showNames) {
- sb.append(names.get(iStarArg));
+ printer.append(names.get(iStarArg));
}
}
for (; i < endMandatoryNamedOnly; i++) {
@@ -485,9 +487,9 @@ public abstract class FunctionSignature implements Serializable {
}
if (kwArg) {
show.comma();
- sb.append("**");
+ printer.append("**");
if (showNames) {
- sb.append(names.get(iKwArg));
+ printer.append(names.get(iKwArg));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/GlobList.java b/src/main/java/com/google/devtools/build/lib/syntax/GlobList.java
index a95c7deb6c..260c318f1f 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/GlobList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/GlobList.java
@@ -21,9 +21,9 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.util.Preconditions;
-
import java.util.ArrayList;
import java.util.List;
@@ -132,7 +132,7 @@ public final class GlobList<E> extends ForwardingList<E> implements SkylarkValue
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.printList(buffer, this, false, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.printList(this, false);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java b/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java
index fbf145bd42..47a6ea646d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java
@@ -88,10 +88,11 @@ public final class ListLiteral extends Expression {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- Printer.printList(sb, exprs, isTuple(), '"', Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT,
+ return Printer.printAbbreviatedList(
+ exprs,
+ isTuple(),
+ Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT,
Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH);
- return sb.toString();
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index 3b1a7c03c6..5c5905b9f4 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -1613,25 +1613,35 @@ public class MethodLibrary {
}
};
- @SkylarkSignature(name = "str", returnType = String.class, doc =
- "Converts any object to string. This is useful for debugging."
- + "<pre class=\"language-python\">str(\"ab\") == \"ab\"</pre>",
- parameters = {@Param(name = "x", doc = "The object to convert.")})
- private static final BuiltinFunction str = new BuiltinFunction("str") {
- public String invoke(Object x) {
- return Printer.str(x);
- }
- };
+ @SkylarkSignature(
+ name = "str",
+ returnType = String.class,
+ doc =
+ "Converts any object to string. This is useful for debugging."
+ + "<pre class=\"language-python\">str(\"ab\") == \"ab\"</pre>",
+ parameters = {@Param(name = "x", doc = "The object to convert.")}
+ )
+ private static final BuiltinFunction str =
+ new BuiltinFunction("str") {
+ public String invoke(Object x) {
+ return Printer.getPrinter().str(x).toString();
+ }
+ };
- @SkylarkSignature(name = "repr", returnType = String.class, doc =
- "Converts any object to a string representation. This is useful for debugging.<br>"
- + "<pre class=\"language-python\">str(\"ab\") == \\\"ab\\\"</pre>",
- parameters = {@Param(name = "x", doc = "The object to convert.")})
- private static final BuiltinFunction repr = new BuiltinFunction("repr") {
- public String invoke(Object x) {
- return Printer.repr(x);
- }
- };
+ @SkylarkSignature(
+ name = "repr",
+ returnType = String.class,
+ doc =
+ "Converts any object to a string representation. This is useful for debugging.<br>"
+ + "<pre class=\"language-python\">str(\"ab\") == \\\"ab\\\"</pre>",
+ parameters = {@Param(name = "x", doc = "The object to convert.")}
+ )
+ private static final BuiltinFunction repr =
+ new BuiltinFunction("repr") {
+ public String invoke(Object x) {
+ return Printer.getPrinter().repr(x).toString();
+ }
+ };
@SkylarkSignature(name = "bool", returnType = Boolean.class,
doc = "Constructor for the bool type. "
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
index fde22dc946..0a581777d8 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
@@ -16,7 +16,9 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintableValue;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -28,394 +30,167 @@ import java.util.Map;
import java.util.MissingFormatWidthException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.annotation.Nullable;
-/**
- * (Pretty) Printing of Skylark values
- */
-public final class Printer {
+/** (Pretty) Printing of Skylark values */
+public class Printer {
- private static final char SKYLARK_QUOTATION_MARK = '"';
+ public static final char SKYLARK_QUOTATION_MARK = '"';
/*
- * Suggested maximum number of list elements that should be printed via printList().
+ * Suggested maximum number of list elements that should be printed via printAbbreviatedList().
* By default, this setting is not considered and no limitation takes place.
*/
- static final int SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT = 4;
+ public static final int SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT = 4;
/*
- * Suggested limit for printList() to shorten the values of list elements when their combined
- * string length reaches this value.
+ * Suggested limit for printAbbreviatedList() to shorten the values of list elements when
+ * their combined string length reaches this value.
* By default, this setting is not considered and no limitation takes place.
*/
- static final int SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH = 32;
-
- private Printer() {
- }
+ public static final int SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH = 32;
/**
- * Get an informal representation of object x.
- * Currently only differs from repr in the behavior for strings and labels at top-level,
- * that are returned as is rather than quoted.
- * @param quotationMark The quotation mark to be used (' or ")
- * @return the representation.
+ * Creates an instance of BasePrinter that wraps an existing buffer.
+ * @param buffer an Appendable
+ * @return new BasePrinter
*/
- public static String str(Object x, char quotationMark) {
- return print(new StringBuilder(), x, quotationMark).toString();
- }
-
- public static String str(Object x) {
- return str(x, SKYLARK_QUOTATION_MARK);
+ public static BasePrinter getPrinter(Appendable buffer) {
+ return new BasePrinter(buffer);
}
/**
- * Get an official representation of object x.
- * For regular data structures, the value should be parsable back into an equal data structure.
- * @param quotationMark The quotation mark to be used (' or ")
- * @return the representation.
+ * Creates an instance of BasePrinter with an empty buffer.
+ * @return new BasePrinter
*/
- public static String repr(Object x, char quotationMark) {
- return write(new StringBuilder(), x, quotationMark).toString();
+ public static BasePrinter getPrinter() {
+ return getPrinter(new StringBuilder());
}
- public static String repr(Object x) {
- return repr(x, SKYLARK_QUOTATION_MARK);
- }
+ private Printer() {}
+
+ // These static methods proxy to the similar methods of BasePrinter
- // In absence of a Python naming tradition, the write() vs print() function names
- // follow the Lisp tradition: print() displays the informal representation (as in Python str)
- // whereas write() displays a readable representation (as in Python repr).
/**
- * Print an informal representation of object x.
- * Currently only differs from repr in the behavior for strings and labels at top-level,
- * that are returned as is rather than quoted.
- * @param buffer the Appendable to which to print the representation
- * @param o the object
- * @param quotationMark The quotation mark to be used (' or ")
- * @return the buffer, in fluent style
+ * Format an object with Skylark's {@code str}.
*/
- private static Appendable print(Appendable buffer, Object o, char quotationMark) {
- if (o instanceof SkylarkPrintableValue) {
- ((SkylarkPrintableValue) o).print(buffer, quotationMark);
- return buffer;
- }
-
- if (o instanceof String) {
- return append(buffer, (String) o);
- }
- return write(buffer, o, quotationMark);
- }
-
- private static Appendable print(Appendable buffer, Object o) {
- return print(buffer, o, SKYLARK_QUOTATION_MARK);
+ public static String str(Object x) {
+ return getPrinter().str(x).toString();
}
/**
- * Print an official representation of object x.
- * For regular data structures, the value should be parsable back into an equal data structure.
- * @param buffer the Appendable to write to.
- * @param o the string a representation of which to write.
- * @param quotationMark The quotation mark to be used (' or ")
- * @return the Appendable, in fluent style.
+ * Format an object with Skylark's {@code repr}.
*/
- public static Appendable write(Appendable buffer, Object o, char quotationMark) {
- if (o == null) {
- throw new NullPointerException(); // Java null is not a build language value.
-
- } else if (o instanceof SkylarkValue) {
- ((SkylarkValue) o).write(buffer, quotationMark);
-
- } else if (o instanceof String) {
- writeString(buffer, (String) o, quotationMark);
-
- } else if (o instanceof Integer || o instanceof Double) {
- append(buffer, o.toString());
-
- } else if (o == Boolean.TRUE) {
- append(buffer, "True");
-
- } else if (o == Boolean.FALSE) {
- append(buffer, "False");
-
- } else if (o instanceof List<?>) {
- List<?> seq = (List<?>) o;
- printList(buffer, seq, false, quotationMark);
-
- } else if (o instanceof Map<?, ?>) {
- Map<?, ?> dict = (Map<?, ?>) o;
- printList(buffer, dict.entrySet(), "{", ", ", "}", null, quotationMark);
-
- } else if (o instanceof Map.Entry<?, ?>) {
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
- write(buffer, entry.getKey(), quotationMark);
- append(buffer, ": ");
- write(buffer, entry.getValue(), quotationMark);
-
- } else if (o instanceof PathFragment) {
- append(buffer, ((PathFragment) o).getPathString());
-
- } else if (o instanceof Class<?>) {
- append(buffer, EvalUtils.getDataTypeNameFromClass((Class<?>) o));
-
- } else {
- append(buffer, o.toString());
- }
-
- return buffer;
- }
-
- public static Appendable write(Appendable buffer, Object o) {
- return write(buffer, o, SKYLARK_QUOTATION_MARK);
- }
-
- // Throughout this file, we transform IOException into AssertionError.
- // During normal operations, we only use in-memory Appendable-s that
- // cannot cause an IOException.
- public static Appendable append(Appendable buffer, char c) {
- try {
- return buffer.append(c);
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
-
- public static Appendable append(Appendable buffer, CharSequence s) {
- try {
- return buffer.append(s);
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
-
- private static Appendable append(Appendable buffer, CharSequence s, int start, int end) {
- try {
- return buffer.append(s, start, end);
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
-
- private static Appendable backslashChar(Appendable buffer, char c) {
- return append(append(buffer, '\\'), c);
- }
-
- private static Appendable escapeCharacter(Appendable buffer, char c, char quote) {
- if (c == quote) {
- return backslashChar(buffer, c);
- }
- switch (c) {
- case '\\':
- return backslashChar(buffer, '\\');
- case '\r':
- return backslashChar(buffer, 'r');
- case '\n':
- return backslashChar(buffer, 'n');
- case '\t':
- return backslashChar(buffer, 't');
- default:
- if (c < 32) {
- return append(buffer, String.format("\\x%02x", (int) c));
- }
- return append(buffer, c); // no need to support UTF-8
- } // endswitch
+ public static String repr(Object x) {
+ return getPrinter().repr(x).toString();
}
/**
- * Write a properly escaped Skylark representation of a string to a buffer.
+ * Print a list of object representations.
+ *
+ * <p>The length of the output will be limited when both {@code maxItemsToPrint} and
+ * {@code criticalItemsStringLength} have values greater than zero.
*
- * @param buffer the Appendable to write to.
- * @param s the string a representation of which to write.
- * @param quote the quote character to use, '"' or '\''.
- * @return the Appendable, in fluent style.
+ * @param list the list of objects to repr (each as with repr)
+ * @param before a string to print before the list
+ * @param separator a separator to print between each object
+ * @param after a string to print after the list
+ * @param singletonTerminator null or a string to print after the list if it is a singleton The
+ * singleton case is notably relied upon in python syntax to distinguish a tuple of size one
+ * such as ("foo",) from a merely parenthesized object such as ("foo").
+ * @param maxItemsToPrint the maximum number of elements to be printed.
+ * @param criticalItemsStringLength a soft limit for the total string length of all arguments.
+ * 'Soft' means that this limit may be exceeded because of formatting.
+ * @return string representation.
*/
- private static Appendable writeString(Appendable buffer, String s, char quote) {
- append(buffer, quote);
- int len = s.length();
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- escapeCharacter(buffer, c, quote);
- }
- return append(buffer, quote);
+ public static String printAbbreviatedList(
+ Iterable<?> list,
+ String before,
+ String separator,
+ String after,
+ @Nullable String singletonTerminator,
+ int maxItemsToPrint,
+ int criticalItemsStringLength) {
+ return getPrinter()
+ .printAbbreviatedList(
+ list,
+ before,
+ separator,
+ after,
+ singletonTerminator,
+ maxItemsToPrint,
+ criticalItemsStringLength)
+ .toString();
}
/**
- * Print a list of object representations
- * @param buffer an appendable buffer onto which to write the list.
- * @param list the list of objects to write (each as with repr)
+ * Print a list of object representations.
+ *
+ * @param list the list of objects to repr (each as with repr)
* @param before a string to print before the list
* @param separator a separator to print between each object
* @param after a string to print after the list
- * @param singletonTerminator null or a string to print after the list if it is a singleton
- * The singleton case is notably relied upon in python syntax to distinguish
- * a tuple of size one such as ("foo",) from a merely parenthesized object such as ("foo").
- * @param quotationMark The quotation mark to be used (' or ")
- * @return the Appendable, in fluent style.
+ * @param singletonTerminator null or a string to print after the list if it is a singleton The
+ * singleton case is notably relied upon in python syntax to distinguish a tuple of size one
+ * such as ("foo",) from a merely parenthesized object such as ("foo").
+ * @return string representation.
*/
- public static Appendable printList(
- Appendable buffer,
+ public static String printAbbreviatedList(
Iterable<?> list,
String before,
String separator,
String after,
- String singletonTerminator,
- char quotationMark) {
- return printList(
- buffer, list, before, separator, after, singletonTerminator, quotationMark, -1, -1);
+ @Nullable String singletonTerminator) {
+ return printAbbreviatedList(list, before, separator, after, singletonTerminator,
+ SUGGESTED_CRITICAL_LIST_ELEMENTS_COUNT, SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH);
}
/**
* Print a list of object representations.
*
- * <p>The length of the output will be limited when both {@code maxItemsToPrint} and {@code
- * criticalItemsStringLength} have values greater than zero.
+ * <p>The length of the output will be limited when both {@code maxItemsToPrint} and
+ * {@code criticalItemsStringLength} have values greater than zero.
*
- * @param buffer an appendable buffer onto which to write the list.
- * @param list the list of objects to write (each as with repr)
- * @param before a string to print before the list
- * @param separator a separator to print between each object
- * @param after a string to print after the list
- * @param singletonTerminator null or a string to print after the list if it is a singleton
- * The singleton case is notably relied upon in python syntax to distinguish
- * a tuple of size one such as ("foo",) from a merely parenthesized object such as ("foo").
- * @param quotationMark The quotation mark to be used (' or ")
+ * @param list the list of objects to repr (each as with repr)
+ * @param isTuple if true the list will be formatted with parentheses and with a trailing comma
+ * in case of one-element tuples.
* @param maxItemsToPrint the maximum number of elements to be printed.
* @param criticalItemsStringLength a soft limit for the total string length of all arguments.
- * 'Soft' means that this limit may be exceeded because of formatting.
- * @return the Appendable, in fluent style.
+ * 'Soft' means that this limit may be exceeded because of formatting.
+ * @return string representation.
*/
- public static Appendable printList(Appendable buffer, Iterable<?> list, String before,
- String separator, String after, String singletonTerminator, char quotationMark,
- int maxItemsToPrint, int criticalItemsStringLength) {
- append(buffer, before);
- int len = 0;
- // Limits the total length of the string representation of the elements, if specified.
- if (maxItemsToPrint > 0 && criticalItemsStringLength > 0) {
- len = appendListElements(LengthLimitedAppendable.create(buffer, criticalItemsStringLength),
- list, separator, quotationMark, maxItemsToPrint);
- } else {
- len = appendListElements(buffer, list, separator, quotationMark);
- }
- if (singletonTerminator != null && len == 1) {
- append(buffer, singletonTerminator);
- }
- return append(buffer, after);
- }
-
- public static Appendable printList(Appendable buffer, Iterable<?> list, String before,
- String separator, String after, String singletonTerminator, int maxItemsToPrint,
+ public static String printAbbreviatedList(
+ Iterable<?> list,
+ boolean isTuple,
+ int maxItemsToPrint,
int criticalItemsStringLength) {
- return printList(buffer, list, before, separator, after, singletonTerminator,
- SKYLARK_QUOTATION_MARK, maxItemsToPrint, criticalItemsStringLength);
- }
-
- /**
- * Appends the given elements to the specified {@link Appendable} and returns the number of
- * elements.
- */
- private static int appendListElements(
- Appendable appendable, Iterable<?> list, String separator, char quotationMark) {
- boolean printSeparator = false; // don't print the separator before the first element
- int len = 0;
- for (Object o : list) {
- if (printSeparator) {
- append(appendable, separator);
- }
- write(appendable, o, quotationMark);
- printSeparator = true;
- len++;
- }
- return len;
+ return getPrinter()
+ .printAbbreviatedList(list, isTuple, maxItemsToPrint, criticalItemsStringLength)
+ .toString();
}
/**
- * Tries to append the given elements to the specified {@link Appendable} until specific limits
- * are reached.
- * @return the number of appended elements.
- */
- private static int appendListElements(LengthLimitedAppendable appendable, Iterable<?> list,
- String separator, char quotationMark, int maxItemsToPrint) {
- boolean printSeparator = false; // don't print the separator before the first element
- boolean skipArgs = false;
- int items = Iterables.size(list);
- int len = 0;
- // We don't want to print "1 more arguments", hence we don't skip arguments if there is only one
- // above the limit.
- int itemsToPrint = (items - maxItemsToPrint == 1) ? items : maxItemsToPrint;
- appendable.enforceLimit();
- for (Object o : list) {
- // We don't want to print "1 more arguments", even if we hit the string limit.
- if (len == itemsToPrint || (appendable.hasHitLimit() && len < items - 1)) {
- skipArgs = true;
- break;
- }
- if (printSeparator) {
- append(appendable, separator);
- }
- write(appendable, o, quotationMark);
- printSeparator = true;
- len++;
- }
- appendable.ignoreLimit();
- if (skipArgs) {
- append(appendable, separator);
- append(appendable, String.format("<%d more arguments>", items - len));
- }
- return len;
- }
-
- public static Appendable printList(Appendable buffer, Iterable<?> list, String before,
- String separator, String after, String singletonTerminator) {
- return printList(
- buffer, list, before, separator, after, singletonTerminator, SKYLARK_QUOTATION_MARK);
- }
-
- /**
- * Print a Skylark list or tuple of object representations
- * @param buffer an appendable buffer onto which to write the list.
- * @param list the contents of the list or tuple
- * @param isTuple is it a tuple or a list?
- * @param quotationMark The quotation mark to be used (' or ")
- * @param maxItemsToPrint the maximum number of elements to be printed.
- * @param criticalItemsStringLength a soft limit for the total string length of all arguments.
- * 'Soft' means that this limit may be exceeded because of formatting.
- * @return the Appendable, in fluent style.
+ * Perform Python-style string formatting, as per pattern % tuple Limitations: only %d %s %r %%
+ * are supported.
+ *
+ * @param pattern a format string.
+ * @param arguments an array containing positional arguments.
+ * @return the formatted string.
*/
- public static Appendable printList(Appendable buffer, Iterable<?> list, boolean isTuple,
- char quotationMark, int maxItemsToPrint, int criticalItemsStringLength) {
- if (isTuple) {
- return printList(buffer, list, "(", ", ", ")", ",", quotationMark, maxItemsToPrint,
- criticalItemsStringLength);
- } else {
- return printList(buffer, list, "[", ", ", "]", null, quotationMark, maxItemsToPrint,
- criticalItemsStringLength);
- }
- }
-
- public static Appendable printList(
- Appendable buffer, Iterable<?> list, boolean isTuple, char quotationMark) {
- return printList(buffer, list, isTuple, quotationMark, -1, -1);
+ public static String format(String pattern, Object... arguments) {
+ return getPrinter().format(pattern, arguments).toString();
}
/**
- * Print a list of object representations
- * @param list the list of objects to write (each as with repr)
- * @param before a string to print before the list
- * @param separator a separator to print between each object
- * @param after a string to print after the list
- * @param singletonTerminator null or a string to print after the list if it is a singleton
- * The singleton case is notably relied upon in python syntax to distinguish
- * a tuple of size one such as ("foo",) from a merely parenthesized object such as ("foo").
- * @param quotationMark The quotation mark to be used (' or ")
- * @return a String, the representation.
+ * Perform Python-style string formatting, as per pattern % tuple Limitations: only %d %s %r %%
+ * are supported.
+ *
+ * @param pattern a format string.
+ * @param arguments a tuple containing positional arguments.
+ * @return the formatted string.
*/
- public static String listString(Iterable<?> list, String before, String separator, String after,
- String singletonTerminator, char quotationMark) {
- return printList(new StringBuilder(), list, before, separator, after, singletonTerminator,
- quotationMark).toString();
- }
-
- public static String listString(
- Iterable<?> list, String before, String separator, String after, String singletonTerminator) {
- return listString(list, before, separator, after, singletonTerminator, SKYLARK_QUOTATION_MARK);
+ public static String formatWithList(String pattern, List<?> arguments) {
+ return getPrinter().formatWithList(pattern, arguments).toString();
}
/**
@@ -428,115 +203,57 @@ public final class Printer {
public static Formattable formattable(final String pattern, Object... arguments) {
final ImmutableList<Object> args = ImmutableList.copyOf(arguments);
return new Formattable() {
- @Override
- public String toString() {
- return formatToString(pattern, args);
- }
+ @Override
+ public String toString() {
+ return formatWithList(pattern, args);
+ }
- @Override
- public void formatTo(Formatter formatter, int flags, int width, int precision) {
- Printer.formatTo(formatter.out(), pattern, args);
- }
- };
+ @Override
+ public void formatTo(Formatter formatter, int flags, int width, int precision) {
+ Printer.getPrinter(formatter.out()).formatWithList(pattern, args);
+ }
+ };
}
/**
- * Perform Python-style string formatting.
+ * Append a char to a buffer. In case of {@link IOException} throw an {@link AssertionError}
+ * instead
*
- * @param pattern a format string.
- * @param arguments a tuple containing positional arguments.
- * @return the formatted string.
+ * @return buffer
*/
- public static String format(String pattern, Object... arguments) {
- return formatToString(pattern, ImmutableList.copyOf(arguments));
+ public static Appendable append(Appendable buffer, char c) {
+ try {
+ return buffer.append(c);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
}
/**
- * Perform Python-style string formatting.
+ * Append a char sequence to a buffer. In case of {@link IOException} throw an
+ * {@link AssertionError} instead
*
- * @param pattern a format string.
- * @param arguments a tuple containing positional arguments.
- * @return the formatted string.
+ * @return buffer
*/
- public static String formatToString(String pattern, List<?> arguments) {
- return formatTo(new StringBuilder(), pattern, arguments).toString();
+ public static Appendable append(Appendable buffer, CharSequence s) {
+ try {
+ return buffer.append(s);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
}
/**
- * Perform Python-style string formatting, as per pattern % tuple
- * Limitations: only %d %s %r %% are supported.
- *
- * @param buffer an Appendable to output to.
- * @param pattern a format string.
- * @param arguments a list containing positional arguments.
- * @return the buffer, in fluent style.
+ * Append a char sequence range to a buffer. In case of {@link IOException} throw an
+ * {@link AssertionError} instead
+ * @return buffer
*/
- // TODO(bazel-team): support formatting arguments, and more complex Python patterns.
- public static Appendable formatTo(Appendable buffer, String pattern, List<?> arguments) {
- // N.B. MissingFormatWidthException is the only kind of IllegalFormatException
- // whose constructor can take and display arbitrary error message, hence its use below.
-
- int length = pattern.length();
- int argLength = arguments.size();
- int i = 0; // index of next character in pattern
- int a = 0; // index of next argument in arguments
-
- while (i < length) {
- int p = pattern.indexOf('%', i);
- if (p == -1) {
- append(buffer, pattern, i, length);
- break;
- }
- if (p > i) {
- append(buffer, pattern, i, p);
- }
- if (p == length - 1) {
- throw new MissingFormatWidthException(
- "incomplete format pattern ends with %: " + repr(pattern));
- }
- char directive = pattern.charAt(p + 1);
- i = p + 2;
- switch (directive) {
- case '%':
- append(buffer, '%');
- continue;
- case 'd':
- case 'r':
- case 's':
- if (a >= argLength) {
- throw new MissingFormatWidthException("not enough arguments for format pattern "
- + repr(pattern) + ": "
- + repr(Tuple.copyOf(arguments)));
- }
- Object argument = arguments.get(a++);
- switch (directive) {
- case 'd':
- if (argument instanceof Integer) {
- append(buffer, argument.toString());
- continue;
- } else {
- throw new MissingFormatWidthException(
- "invalid argument " + repr(argument) + " for format pattern %d");
- }
- case 'r':
- write(buffer, argument);
- continue;
- case 's':
- print(buffer, argument);
- continue;
- }
- // fall through
- default:
- throw new MissingFormatWidthException(
- "unsupported format character " + repr(String.valueOf(directive))
- + " at index " + (p + 1) + " in " + repr(pattern));
- }
- }
- if (a < argLength) {
- throw new MissingFormatWidthException(
- "not all arguments converted during string formatting");
+ private static Appendable append(Appendable buffer, CharSequence s, int start, int end) {
+ try {
+ return buffer.append(s, start, end);
+ } catch (IOException e) {
+ throw new AssertionError(e);
}
- return buffer;
}
/**
@@ -563,7 +280,7 @@ public final class Printer {
this.limit = limit;
}
- public static LengthLimitedAppendable create(Appendable original, int limit) {
+ private static LengthLimitedAppendable create(Appendable original, int limit) {
// We don't want to overwrite the limit if original is already an instance of this class.
return (original instanceof LengthLimitedAppendable)
? (LengthLimitedAppendable) original : new LengthLimitedAppendable(original, limit);
@@ -650,12 +367,12 @@ public final class Printer {
@Override
public Appendable append(CharSequence csq, int start, int end) throws IOException {
- return append(csq.subSequence(start, end));
+ return this.append(csq.subSequence(start, end));
}
@Override
public Appendable append(char c) throws IOException {
- return append(String.valueOf(c));
+ return this.append(String.valueOf(c));
}
public boolean hasHitLimit() {
@@ -675,4 +392,404 @@ public final class Printer {
return original.toString();
}
}
+
+ /** Actual class that implements Printer API */
+ public static final class BasePrinter implements SkylarkPrinter {
+ // Methods of this class should not recurse through static methods of Printer
+
+ private final Appendable buffer;
+
+ /**
+ * Creates a printer instance.
+ *
+ * @param buffer the Appendable to which to print the representation
+ */
+ private BasePrinter(Appendable buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public String toString() {
+ return buffer.toString();
+ }
+
+ /**
+ * Print an informal representation of object x. Currently only differs from repr in the
+ * behavior for strings and labels at top-level, that are returned as is rather than quoted.
+ *
+ * @param o the object
+ * @return the buffer, in fluent style
+ */
+ public BasePrinter str(Object o) {
+ if (o instanceof SkylarkPrintableValue) {
+ ((SkylarkPrintableValue) o).str(this);
+ return this;
+ }
+
+ if (o instanceof String) {
+ return this.append((String) o);
+ }
+ return this.repr(o);
+ }
+
+ /**
+ * Print an official representation of object x. For regular data structures, the value should
+ * be parsable back into an equal data structure.
+ *
+ * @param o the string a representation of which to repr.
+ * @return BasePrinter.
+ */
+ @Override
+ public BasePrinter repr(Object o) {
+ if (o == null) {
+ throw new NullPointerException(); // Java null is not a valid Skylark value.
+
+ } else if (o instanceof SkylarkValue) {
+ ((SkylarkValue) o).repr(this);
+
+ } else if (o instanceof String) {
+ writeString((String) o);
+
+ } else if (o instanceof Integer || o instanceof Double) {
+ this.append(o.toString());
+
+ } else if (o == Boolean.TRUE) {
+ this.append("True");
+
+ } else if (o == Boolean.FALSE) {
+ this.append("False");
+
+ } else if (o instanceof Map<?, ?>) {
+ Map<?, ?> dict = (Map<?, ?>) o;
+ this.printList(dict.entrySet(), "{", ", ", "}", null);
+
+ } else if (o instanceof List<?>) {
+ List<?> seq = (List<?>) o;
+ this.printList(seq, false);
+
+ } else if (o instanceof Map.Entry<?, ?>) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ this.repr(entry.getKey());
+ this.append(": ");
+ this.repr(entry.getValue());
+
+ } else if (o instanceof PathFragment) {
+ this.append(((PathFragment) o).getPathString());
+
+ } else if (o instanceof Class<?>) {
+ this.append(EvalUtils.getDataTypeNameFromClass((Class<?>) o));
+
+ } else if (o instanceof ASTNode || o instanceof Location) {
+ // AST node objects and locations are printed in tracebacks and error messages,
+ // it's safe to print their toString representations
+ this.append(o.toString());
+
+ } else {
+ // TODO(bazel-team): change to a special representation for unknown objects
+ this.append(o.toString());
+ }
+
+ return this;
+ }
+
+ /**
+ * Write a properly escaped Skylark representation of a string to a buffer.
+ *
+ * @param s the string a representation of which to repr.
+ * @return the Appendable, in fluent style.
+ */
+ private BasePrinter writeString(String s) {
+ this.append(SKYLARK_QUOTATION_MARK);
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ escapeCharacter(c);
+ }
+ return this.append(SKYLARK_QUOTATION_MARK);
+ }
+
+ private BasePrinter backslashChar(char c) {
+ return this.append('\\').append(c);
+ }
+
+ private BasePrinter escapeCharacter(char c) {
+ if (c == SKYLARK_QUOTATION_MARK) {
+ return backslashChar(c);
+ }
+ switch (c) {
+ case '\\':
+ return backslashChar('\\');
+ case '\r':
+ return backslashChar('r');
+ case '\n':
+ return backslashChar('n');
+ case '\t':
+ return backslashChar('t');
+ default:
+ if (c < 32) {
+ //TODO(bazel-team): support \x escapes
+ return this.append(String.format("\\x%02x", (int) c));
+ }
+ return this.append(c); // no need to support UTF-8
+ } // endswitch
+ }
+
+ /**
+ * Print a list of object representations
+ *
+ * @param list the list of objects to repr (each as with repr)
+ * @param before a string to print before the list items, e.g. an opening bracket
+ * @param separator a separator to print between items
+ * @param after a string to print after the list items, e.g. a closing bracket
+ * @param singletonTerminator null or a string to print after the list if it is a singleton The
+ * singleton case is notably relied upon in python syntax to distinguish a tuple of size one
+ * such as ("foo",) from a merely parenthesized object such as ("foo").
+ * @return the BasePrinter.
+ */
+ @Override
+ public BasePrinter printList(
+ Iterable<?> list,
+ String before,
+ String separator,
+ String after,
+ @Nullable String singletonTerminator) {
+ return printAbbreviatedList(list, before, separator, after, singletonTerminator, -1, -1);
+ }
+
+ /**
+ * Print a list of object representations.
+ *
+ * <p>The length of the output will be limited when both {@code maxItemsToPrint} and {@code
+ * criticalItemsStringLength} have values greater than zero.
+ *
+ * @param list the list of objects to repr (each as with repr)
+ * @param before a string to print before the list
+ * @param separator a separator to print between each object
+ * @param after a string to print after the list
+ * @param singletonTerminator null or a string to print after the list if it is a singleton The
+ * singleton case is notably relied upon in python syntax to distinguish a tuple of size one
+ * such as ("foo",) from a merely parenthesized object such as ("foo").
+ * @param maxItemsToPrint the maximum number of elements to be printed.
+ * @param criticalItemsStringLength a soft limit for the total string length of all arguments.
+ * 'Soft' means that this limit may be exceeded because of formatting.
+ * @return the BasePrinter.
+ */
+ public BasePrinter printAbbreviatedList(
+ Iterable<?> list,
+ String before,
+ String separator,
+ String after,
+ @Nullable String singletonTerminator,
+ int maxItemsToPrint,
+ int criticalItemsStringLength) {
+ this.append(before);
+ int len = 0;
+ // Limits the total length of the string representation of the elements, if specified.
+ if (maxItemsToPrint > 0 && criticalItemsStringLength > 0) {
+ len =
+ appendListElements(
+ LengthLimitedAppendable.create(buffer, criticalItemsStringLength),
+ list,
+ separator,
+ maxItemsToPrint);
+ } else {
+ len = appendListElements(list, separator);
+ }
+ if (singletonTerminator != null && len == 1) {
+ this.append(singletonTerminator);
+ }
+ return this.append(after);
+ }
+
+ /**
+ * Appends the given elements to the specified {@link Appendable} and returns the number of
+ * elements.
+ */
+ private int appendListElements(Iterable<?> list, String separator) {
+ boolean printSeparator = false; // don't print the separator before the first element
+ int len = 0;
+ for (Object o : list) {
+ if (printSeparator) {
+ this.append(separator);
+ }
+ this.repr(o);
+ printSeparator = true;
+ len++;
+ }
+ return len;
+ }
+
+ /**
+ * Tries to append the given elements to the specified {@link Appendable} until specific limits
+ * are reached.
+ *
+ * @return the number of appended elements.
+ */
+ private int appendListElements(
+ LengthLimitedAppendable appendable,
+ Iterable<?> list,
+ String separator,
+ int maxItemsToPrint) {
+ boolean printSeparator = false; // don't print the separator before the first element
+ boolean skipArgs = false;
+ int items = Iterables.size(list);
+ int len = 0;
+ // We don't want to print "1 more arguments", hence we don't skip arguments if there is only
+ // one above the limit.
+ int itemsToPrint = (items - maxItemsToPrint == 1) ? items : maxItemsToPrint;
+ appendable.enforceLimit();
+ for (Object o : list) {
+ // We don't want to print "1 more arguments", even if we hit the string limit.
+ if (len == itemsToPrint || (appendable.hasHitLimit() && len < items - 1)) {
+ skipArgs = true;
+ break;
+ }
+ if (printSeparator) {
+ this.append(separator);
+ }
+ Printer.getPrinter(appendable).repr(o);
+ printSeparator = true;
+ len++;
+ }
+ appendable.ignoreLimit();
+ if (skipArgs) {
+ this.append(separator);
+ this.append(String.format("<%d more arguments>", items - len));
+ }
+ return len;
+ }
+
+ /**
+ * Print a Skylark list or tuple of object representations
+ *
+ * @param list the contents of the list or tuple
+ * @param isTuple if true the list will be formatted with parentheses and with a trailing comma
+ * in case of one-element tuples.
+ * @param maxItemsToPrint the maximum number of elements to be printed.
+ * @param criticalItemsStringLength a soft limit for the total string length of all arguments.
+ * 'Soft' means that this limit may be exceeded because of formatting.
+ * @return the Appendable, in fluent style.
+ */
+ public BasePrinter printAbbreviatedList(
+ Iterable<?> list, boolean isTuple, int maxItemsToPrint, int criticalItemsStringLength) {
+ if (isTuple) {
+ return this.printAbbreviatedList(list, "(", ", ", ")", ",",
+ maxItemsToPrint, criticalItemsStringLength);
+ } else {
+ return this.printAbbreviatedList(list, "[", ", ", "]", null,
+ maxItemsToPrint, criticalItemsStringLength);
+ }
+ }
+
+ @Override
+ public BasePrinter printList(Iterable<?> list, boolean isTuple) {
+ return this.printAbbreviatedList(list, isTuple, -1, -1);
+ }
+
+ /**
+ * Perform Python-style string formatting, as per pattern % tuple Limitations: only %d %s %r %%
+ * are supported.
+ *
+ * @param pattern a format string.
+ * @param arguments an array containing positional arguments.
+ * @return the formatted string.
+ */
+ @Override
+ public BasePrinter format(String pattern, Object... arguments) {
+ return this.formatWithList(pattern, ImmutableList.copyOf(arguments));
+ }
+
+ /**
+ * Perform Python-style string formatting, as per pattern % tuple Limitations: only %d %s %r %%
+ * are supported.
+ *
+ * @param pattern a format string.
+ * @param arguments a tuple containing positional arguments.
+ * @return the formatted string.
+ */
+ @Override
+ public BasePrinter formatWithList(String pattern, List<?> arguments) {
+ // TODO(bazel-team): support formatting arguments, and more complex Python patterns.
+ // N.B. MissingFormatWidthException is the only kind of IllegalFormatException
+ // whose constructor can take and display arbitrary error message, hence its use below.
+
+ int length = pattern.length();
+ int argLength = arguments.size();
+ int i = 0; // index of next character in pattern
+ int a = 0; // index of next argument in arguments
+
+ while (i < length) {
+ int p = pattern.indexOf('%', i);
+ if (p == -1) {
+ Printer.append(buffer, pattern, i, length);
+ break;
+ }
+ if (p > i) {
+ Printer.append(buffer, pattern, i, p);
+ }
+ if (p == length - 1) {
+ throw new MissingFormatWidthException(
+ "incomplete format pattern ends with %: " + this.repr(pattern));
+ }
+ char directive = pattern.charAt(p + 1);
+ i = p + 2;
+ switch (directive) {
+ case '%':
+ this.append('%');
+ continue;
+ case 'd':
+ case 'r':
+ case 's':
+ if (a >= argLength) {
+ throw new MissingFormatWidthException(
+ "not enough arguments for format pattern "
+ + this.repr(pattern)
+ + ": "
+ + this.repr(Tuple.copyOf(arguments)));
+ }
+ Object argument = arguments.get(a++);
+ switch (directive) {
+ case 'd':
+ if (argument instanceof Integer) {
+ this.append(argument.toString());
+ continue;
+ } else {
+ throw new MissingFormatWidthException(
+ "invalid argument " + this.repr(argument) + " for format pattern %d");
+ }
+ case 'r':
+ this.repr(argument);
+ continue;
+ case 's':
+ this.str(argument);
+ continue;
+ }
+ // fall through
+ default:
+ throw new MissingFormatWidthException(
+ // The call to Printer.repr doesn't cause an infinite recursion because it's
+ // only used to format a string properly
+ String.format("unsupported format character \"%s\" at index %s in %s",
+ String.valueOf(directive), p + 1, Printer.repr(pattern)));
+ }
+ }
+ if (a < argLength) {
+ throw new MissingFormatWidthException(
+ "not all arguments converted during string formatting");
+ }
+ return this;
+ }
+
+ @Override
+ public BasePrinter append(char c) {
+ Printer.append(buffer, c);
+ return this;
+ }
+
+ @Override
+ public BasePrinter append(CharSequence s) {
+ Printer.append(buffer, s);
+ return this;
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
index 8f672127e7..e3e2e87dfc 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.util.Preconditions;
@@ -61,8 +62,8 @@ public final class Runtime {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "None");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("None");
}
}
@@ -82,8 +83,8 @@ public final class Runtime {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "<unbound>");
+ public void repr(SkylarkPrinter printer) {
+ printer.append("<unbound>");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java b/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
index 5e72aedcd5..c06089b417 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
@@ -16,9 +16,9 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.util.Preconditions;
-
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -152,8 +152,8 @@ public final class SelectorList implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.printList(buffer, elements, "", " + ", "", null, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.printList(elements, "", " + ", "", null);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java b/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
index 7ff2e8bc2a..20f409f1ca 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
@@ -16,9 +16,9 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
-
import java.util.Map;
import java.util.TreeMap;
@@ -79,8 +79,8 @@ public final class SelectorValue implements SkylarkValue {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.formatTo(buffer, "selector(%r)", Tuple.of(dictionary));
+ public void repr(SkylarkPrinter printer) {
+ printer.formatWithList("selector(%r)", Tuple.of(dictionary));
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java
index 01f104bacb..bfb7dca9cb 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.syntax;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.syntax.SkylarkMutable.MutableMap;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -168,8 +169,8 @@ public final class SkylarkDict<K, V> extends MutableMap<K, V>
// Other methods
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.printList(buffer, entrySet(), "{", ", ", "}", null, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.printList(entrySet(), "{", ", ", "}", null);
}
/**
@@ -191,7 +192,7 @@ public final class SkylarkDict<K, V> extends MutableMap<K, V>
}
throw new EvalException(
null,
- Printer.format(
+ String.format(
"%s is not of expected type dict or NoneType",
description == null ? Printer.repr(obj) : String.format("'%s'", description)));
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
index 7e2ae6035e..c9e3eecd57 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
@@ -19,6 +19,7 @@ import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.syntax.SkylarkMutable.MutableCollection;
import java.util.ArrayList;
import java.util.Collection;
@@ -182,8 +183,8 @@ public abstract class SkylarkList<E> extends MutableCollection<E>
// Other methods
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.printList(buffer, getContentsUnsafe(), isTuple(), quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.printList(getContentsUnsafe(), isTuple());
}
// Note that the following two functions slightly violate the Java List protocol,
@@ -236,7 +237,7 @@ public abstract class SkylarkList<E> extends MutableCollection<E>
return ((SkylarkList<?>) obj).getContents(type, description);
}
throw new EvalException(null,
- Printer.format("Illegal argument: %s is not of expected type list or NoneType",
+ String.format("Illegal argument: %s is not of expected type list or NoneType",
description == null ? Printer.repr(obj) : String.format("'%s'", description)));
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
index 674264cb8c..3d8daeadbe 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
@@ -21,6 +21,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.util.Preconditions;
import java.util.ArrayList;
@@ -321,14 +322,15 @@ public final class SkylarkNestedSet implements SkylarkValue, SkylarkQueryable {
}
@Override
- public void write(Appendable buffer, char quotationMark) {
- Printer.append(buffer, "depset(");
- Printer.printList(buffer, set, "[", ", ", "]", null, quotationMark);
+ public void repr(SkylarkPrinter printer) {
+ printer.append("depset(");
+ printer.printList(set, "[", ", ", "]", null);
Order order = getOrder();
if (order != Order.STABLE_ORDER) {
- Printer.append(buffer, ", order = \"" + order.getSkylarkName() + "\"");
+ printer.append(", order = ");
+ printer.repr(order.getSkylarkName());
}
- Printer.append(buffer, ")");
+ printer.append(")");
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SliceExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/SliceExpression.java
index f3ef2779b3..92d51fe8b4 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SliceExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SliceExpression.java
@@ -107,7 +107,7 @@ public final class SliceExpression extends Expression {
throw new EvalException(
loc,
- Printer.format(
+ String.format(
"type '%s' has no operator [:](%s, %s, %s)",
EvalUtils.getDataTypeName(objValue),
EvalUtils.getDataTypeName(startValue),
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Type.java b/src/main/java/com/google/devtools/build/lib/syntax/Type.java
index da2750d19c..aac5420a5d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Type.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Type.java
@@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
import com.google.devtools.build.lib.util.LoggingUtil;
import com.google.devtools.build.lib.util.StringCanonicalizer;
@@ -249,15 +250,15 @@ public abstract class Type<T> {
*/
public static class ConversionException extends EvalException {
private static String message(Type<?> type, Object value, @Nullable Object what) {
- StringBuilder builder = new StringBuilder();
- builder.append("expected value of type '").append(type).append("'");
+ BasePrinter printer = Printer.getPrinter();
+ printer.append("expected value of type '").append(type.toString()).append("'");
if (what != null) {
- builder.append(" for ").append(what);
+ printer.append(" for ").append(what.toString());
}
- builder.append(", but got ");
- Printer.write(builder, value);
- builder.append(" (").append(EvalUtils.getDataTypeName(value)).append(")");
- return builder.toString();
+ printer.append(", but got ");
+ printer.repr(value);
+ printer.append(" (").append(EvalUtils.getDataTypeName(value)).append(")");
+ return printer.toString();
}
public ConversionException(Type<?> type, Object value, @Nullable Object what) {
diff --git a/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java b/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
index 97a38b25e8..de6d81a257 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
@@ -530,12 +530,6 @@ public class BuildTypeTest {
}
@Test
- public void testSingleQuotes() throws Exception {
- assertThat(Printer.repr(createTestFilesetEntry(), '\''))
- .isEqualTo(createExpectedFilesetEntryString('\''));
- }
-
- @Test
public void testFilesetEntrySymlinkAttr() throws Exception {
FilesetEntry entryDereference =
createTestFilesetEntry(FilesetEntry.SymlinkBehavior.DEREFERENCE);
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
index b4334436a9..888047d871 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
@@ -2728,7 +2728,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase {
assertThat(getConfiguredTarget("//java/com/foo")).isNull();
assertContainsEvent(
"in config_feature_flag rule //java/com/foo:flag1: "
- + "value must be one of ['off', 'on'], but was 'invalid'");
+ + "value must be one of [\"off\", \"on\"], but was \"invalid\"");
}
@Test
@@ -2757,7 +2757,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase {
assertThat(getConfiguredTarget("//java/com/foo")).isNull();
assertContainsEvent(
"in config_feature_flag rule //java/com/foo:flag1: "
- + "value must be one of ['off', 'on'], but was 'invalid'");
+ + "value must be one of [\"off\", \"on\"], but was \"invalid\"");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
index b649872487..0d87489daf 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
@@ -237,7 +237,7 @@ public final class ConfigFeatureFlagTest extends SkylarkTestCase {
assertThat(getConfiguredTarget("//test:flag")).isNull();
assertContainsEvent(
"in allowed_values attribute of config_feature_flag rule //test:flag: "
- + "cannot contain duplicates, but contained multiple of ['double']");
+ + "cannot contain duplicates, but contained multiple of [\"double\"]");
}
@Test
@@ -260,7 +260,7 @@ public final class ConfigFeatureFlagTest extends SkylarkTestCase {
assertThat(getConfiguredTarget("//test:top")).isNull();
assertContainsEvent(
"in default_value attribute of config_feature_flag rule //test:flag: "
- + "must be one of ['eagle', 'legal'], but was 'beagle'");
+ + "must be one of [\"eagle\", \"legal\"], but was \"beagle\"");
}
@Test
@@ -284,7 +284,7 @@ public final class ConfigFeatureFlagTest extends SkylarkTestCase {
// TODO(mstaib): when configurationError is implemented, switch to testing for that
assertContainsEvent(
"in config_feature_flag rule //test:flag: "
- + "value must be one of ['configured', 'default', 'other'], but was 'invalid'");
+ + "value must be one of [\"configured\", \"default\", \"other\"], but was \"invalid\"");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
index afaf9aaab7..2ae31358cb 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
@@ -16,6 +16,8 @@ package com.google.devtools.build.lib.syntax;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
@@ -583,30 +585,54 @@ public class EvaluationTest extends EvaluationTestCase {
newTest().testStatement("not 'a' in ['a'] or 0", 0);
}
- private Object createObjWithStr() {
+ private SkylarkValue createObjWithStr() {
+ return new SkylarkValue() {
+ @Override
+ public void repr(SkylarkPrinter printer) {
+ printer.append("str marker");
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return false;
+ }
+ };
+ }
+
+ private Object createUnknownObj() {
return new Object() {
@Override
public String toString() {
- return "str marker";
+ return "unknown object";
}
};
}
@Test
public void testPercOnObject() throws Exception {
- newTest().update("obj", createObjWithStr()).testStatement("'%s' % obj", "str marker");
+ newTest()
+ .update("obj", createObjWithStr())
+ .testStatement("'%s' % obj", "str marker");
+ newTest()
+ .update("unknown", createUnknownObj())
+ .testStatement("'%s' % unknown", "unknown object");
}
@Test
public void testPercOnObjectList() throws Exception {
- newTest().update("obj", createObjWithStr()).testStatement("'%s %s' % (obj, obj)",
- "str marker str marker");
+ newTest()
+ .update("obj", createObjWithStr())
+ .testStatement("'%s %s' % (obj, obj)", "str marker str marker");
+ newTest()
+ .update("unknown", createUnknownObj())
+ .testStatement("'%s %s' % (unknown, unknown)", "unknown object unknown object");
}
@Test
public void testPercOnObjectInvalidFormat() throws Exception {
- newTest().update("obj", createObjWithStr()).testIfExactError(
- "invalid argument str marker for format pattern %d", "'%d' % obj");
+ newTest()
+ .update("obj", createObjWithStr())
+ .testIfExactError("invalid argument str marker for format pattern %d", "'%d' % obj");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/PrinterTest.java b/src/test/java/com/google/devtools/build/lib/syntax/PrinterTest.java
index 0a7f8410a8..fdf43271bb 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/PrinterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/PrinterTest.java
@@ -98,12 +98,12 @@ public class PrinterTest {
@Test
public void testFormatPositional() throws Exception {
- assertThat(Printer.formatToString("%s %d", Tuple.of("foo", 3))).isEqualTo("foo 3");
+ assertThat(Printer.formatWithList("%s %d", Tuple.of("foo", 3))).isEqualTo("foo 3");
assertThat(Printer.format("%s %d", "foo", 3)).isEqualTo("foo 3");
// Note: formatToString doesn't perform scalar x -> (x) conversion;
// The %-operator is responsible for that.
- assertThat(Printer.formatToString("", Tuple.of())).isEmpty();
+ assertThat(Printer.formatWithList("", Tuple.of())).isEmpty();
assertThat(Printer.format("%s", "foo")).isEqualTo("foo");
assertThat(Printer.format("%s", 3.14159)).isEqualTo("3.14159");
checkFormatPositionalFails("not all arguments converted during string formatting",
@@ -131,34 +131,6 @@ public class PrinterTest {
}
@Test
- public void testSingleQuotes() throws Exception {
- assertThat(Printer.str("test", '\'')).isEqualTo("test");
- assertThat(Printer.repr("test", '\'')).isEqualTo("'test'");
-
- assertThat(Printer.repr("'", '\'')).isEqualTo("'\\''");
- assertThat(Printer.str("\"", '\'')).isEqualTo("\"");
- assertThat(Printer.repr("\"", '\'')).isEqualTo("'\"'");
-
- List<?> list = MutableList.of(null, "foo", "bar");
- List<?> tuple = Tuple.of("foo", "bar");
-
- assertThat(Printer.str(Tuple.of(1, list, 3), '\'')).isEqualTo("(1, ['foo', 'bar'], 3)");
- assertThat(Printer.repr(Tuple.of(1, list, 3), '\'')).isEqualTo("(1, ['foo', 'bar'], 3)");
- assertThat(Printer.str(MutableList.of(null, 1, tuple, 3), '\''))
- .isEqualTo("[1, ('foo', 'bar'), 3]");
- assertThat(Printer.repr(MutableList.of(null, 1, tuple, 3), '\''))
- .isEqualTo("[1, ('foo', 'bar'), 3]");
-
- Map<Object, Object> dict =
- ImmutableMap.<Object, Object>of(1, tuple, 2, list, "foo", MutableList.of(null));
-
- assertThat(Printer.str(dict, '\''))
- .isEqualTo("{1: ('foo', 'bar'), 2: ['foo', 'bar'], 'foo': []}");
- assertThat(Printer.repr(dict, '\''))
- .isEqualTo("{1: ('foo', 'bar'), 2: ['foo', 'bar'], 'foo': []}");
- }
-
- @Test
public void testListLimitStringLength() throws Exception {
int lengthDivisibleByTwo = Printer.SUGGESTED_CRITICAL_LIST_ELEMENTS_STRING_LENGTH;
if (lengthDivisibleByTwo % 2 == 1) {
@@ -249,9 +221,7 @@ public class PrinterTest {
}
private String printList(List<?> list, int criticalElementsCount, int criticalStringLength) {
- StringBuilder builder = new StringBuilder();
- Printer.printList(
- builder, list, "[", ", ", "]", "", '"', criticalElementsCount, criticalStringLength);
- return builder.toString();
+ return Printer.printAbbreviatedList(
+ list, "[", ", ", "]", "", criticalElementsCount, criticalStringLength);
}
}