Skylark: write labels readably

Write a label as Label("//x:x") instead of merely "//x:x", so it can be read
and evaluated back, as per the Python convention. However, the OutputFormatter
for BUILD files still needs to output "//x:x".

--
MOS_MIGRATED_REVID=96209979
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 2643246..baade5a 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
@@ -25,6 +25,7 @@
 import com.google.devtools.build.lib.packages.PackageSerializer;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.syntax.Environment;
 import com.google.devtools.build.lib.syntax.EvalUtils;
 import com.google.devtools.build.lib.syntax.Label;
 import com.google.devtools.build.lib.syntax.Printer;
@@ -289,6 +290,46 @@
       return "build";
     }
 
+    // We only need to be able to output the types allowed in an attribute:
+    // int, string, label, string_list, label_list, bool, output, output_list, string_dict, license,
+    // where most of those things are actually printed as strings and list of strings.
+    private static void outputValue(PrintStream out, Object value) {
+      if (value instanceof Integer || value instanceof Boolean || value == Environment.NONE) {
+        Printer.write(out, value);
+      } else if (value instanceof String) {
+        Printer.writeString(out, (String) value, '"');
+      } else if (value instanceof Label) {
+        outputValue(out, value.toString());
+      } else if (value instanceof List<?>) {
+        out.print("[");
+        outputList(out, (List<?>) value);
+        out.print("]");
+      } else if (value instanceof Map<?, ?>) {
+        Map<?, ?> dict = (Map<?, ?>) value;
+        out.print("{");
+        outputList(out, dict.entrySet());
+        out.print("}");
+      } else if (value instanceof Map.Entry<?, ?>) {
+        Map.Entry<?, ?> entry = (Map.Entry<?, ?>) value;
+        outputValue(out, entry.getKey());
+        out.print(": ");
+        outputValue(out, entry.getValue());
+      } else {
+        throw new RuntimeException("invalid value " + Printer.repr(value));
+      }
+    }
+
+    private static void outputList(PrintStream out, Iterable<?> list) {
+      boolean first = true;
+      for (Object v : list) {
+        if (!first) {
+          out.print(", ");
+          first = false;
+        }
+        outputValue(out, v);
+      }
+    }
+
     private void outputRule(Rule rule, PrintStream out) {
       out.printf("# %s%n", rule.getLocation());
       out.printf("%s(%n", rule.getRuleClass());
@@ -310,7 +351,7 @@
           // Display it as a list (and not as a tuple). Attributes can never be tuples.
           value = new ArrayList<>((List<?>) value);
         }
-        Printer.write(out, value);
+        outputValue(out, value);
         out.println(",");
       }
       out.printf(")\n%n");
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 56f129e..f3e95259 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
@@ -135,7 +135,9 @@
       append(buffer, "<function " + func.getName() + ">");
 
     } else if (o instanceof Label) {
+      append(buffer, "Label(");
       write(buffer, o.toString());
+      append(buffer, ')');
 
     } else if (o instanceof FilesetEntry) {
            FilesetEntry entry = (FilesetEntry) o;
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 d963741..aac213e 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
@@ -70,7 +70,7 @@
     assertEquals("None", Printer.repr(Environment.NONE));
 
     assertEquals("//x:x", Printer.str(Label.parseAbsolute("//x")));
-    assertEquals("\"//x:x\"", Printer.repr(Label.parseAbsolute("//x")));
+    assertEquals("Label(\"//x:x\")", Printer.repr(Label.parseAbsolute("//x")));
 
     List<?> list = makeList("foo", "bar");
     List<?> tuple = makeTuple("foo", "bar");