Revision: 5168
Author:   [email protected]
Date:     Thu Nov 29 12:27:35 2012
Log:      Refactor HtmlDefinitions JS emission.
https://codereview.appspot.com/6782129

* Build the quoted-key Closure-compatibility exports into the definition
  generators, so that there is no list at the end of the file to forget
  to update.
* Merge duplicate code in the two entry points HtmlDefinitions$Builder
  and HtmlDefinitions.main; the latter now produces output identical to
  the former (it is not used from code, so I assume it is intended for
  debugging).

[email protected]

http://code.google.com/p/google-caja/source/detail?r=5168

Modified:
 /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java

=======================================
--- /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java Tue Nov 13 10:21:28 2012 +++ /trunk/src/com/google/caja/lang/html/HtmlDefinitions.java Thu Nov 29 12:27:35 2012
@@ -107,7 +107,17 @@
   private static final AttribKey SCRIPT_SRC = AttribKey.forHtmlAttrib(
       ElKey.forHtmlElement("script"), "src");

-  private static <U> ExpressionStmt mapFromEnum(
+  private static Statement export(String key, Expression e) {
+    FilePosition unk = FilePosition.UNKNOWN;
+    // The html4[@k] assignment is an explicit export for Closure Compiler
+    return (Statement) QuasiBuilder.substV(
+            "{ html4.@i = @e; html4[@k] = html4.@i; }",
+            "i", new Reference(new Identifier(unk, key)),
+            "k", new StringLiteral(unk, key),
+            "e", e);
+  }
+
+  private static <U> Statement mapFromEnum(
       Iterable<U> entries, String key,
       Function<U, String> keyMaker, Function<U, Integer> valueMaker) {
     FilePosition unk = FilePosition.UNKNOWN;
@@ -120,12 +130,11 @@
       keys.add(new StringLiteral(unk, quoted));
       values.add(new IntegerLiteral(unk, valueMaker.apply(e)));
     }
-    return new ExpressionStmt(unk,
-        (Expression) QuasiBuilder.substV(
-            "html4.@i = { @k*: @v* };",
-            "i", new Reference(new Identifier(unk, key)),
-            "k", new ParseTreeNodeContainer(keys),
-            "v", new ParseTreeNodeContainer(values)));
+    return export(key, (Expression) QuasiBuilder.substV(
+        "({ @k*: @v* })",
+        "i", new Reference(new Identifier(unk, key)),
+        "k", new ParseTreeNodeContainer(keys),
+        "v", new ParseTreeNodeContainer(values)));
   }

   /**
@@ -133,7 +142,7 @@
* should stringify to the JS keys and whose values are mapped by the function
    * {@code codegen}.
    */
-  private static <T> ExpressionStmt mapFromMap(
+  private static <T> Statement mapFromMap(
       Map<?, T> entries, String key, Function<T, Expression> codegen) {
     final FilePosition unk = FilePosition.UNKNOWN;
     List<StringLiteral> keys = new ArrayList<StringLiteral>();
@@ -142,13 +151,10 @@
       keys.add(StringLiteral.valueOf(unk, e.getKey().toString()));
       values.add(codegen.apply(e.getValue()));
     }
-    ExpressionStmt def = new ExpressionStmt(unk, (Expression)
-        QuasiBuilder.substV(
-            "html4.@i = { @k*: @v* };",
-            "i", new Reference(new Identifier(unk, key)),
-            "k", new ParseTreeNodeContainer(keys),
-            "v", new ParseTreeNodeContainer(values)));
-    return def;
+    return export(key, (Expression) QuasiBuilder.substV(
+        "({ @k*: @v* })",
+        "k", new ParseTreeNodeContainer(keys),
+        "v", new ParseTreeNodeContainer(values)));
   }

   public static Block generateJavascriptDefinitions(HtmlSchema schema) {
@@ -190,9 +196,9 @@
values.add(new IntegerLiteral(unk, A_TYPE_MAP.get(e.getValue())));
         }
       }
-      definitions.appendChild(new ExpressionStmt(unk, (Expression)
-          QuasiBuilder.substV(
-              "html4.ATTRIBS = { @k*: @v* };",
+      definitions.appendChild(export("ATTRIBS",
+          (Expression) QuasiBuilder.substV(
+              "({ @k*: @v* })",
               "k", new ParseTreeNodeContainer(keys),
               "v", new ParseTreeNodeContainer(values))));
     }
@@ -469,6 +475,45 @@
     }
     return data;
   }
+
+  private static void generateSourceText(HtmlSchema schema, Writer out)
+      throws IOException {
+    String currentDate = "" + new Date();
+    if (currentDate.indexOf("\n") >= 0) {
+ throw new SomethingWidgyHappenedError("Date should not contain newline");
+    }
+    out.write("// Copyright Google Inc.\n");
+    out.write("// Licensed under the Apache Licence Version 2.0\n");
+    out.write("// Autogenerated at " + currentDate + "\n");
+    out.write("// @overrides window\n");
+    out.write("// @provides html4\n");
+    Block node = generateJavascriptDefinitions(schema);
+    RenderContext rc = new RenderContext(node.makeRenderer(out, null))
+        .withPropertyNameQuotingMode(
+            PropertyNameQuotingMode.PRESERVE_QUOTES);
+    renderFlattenedBlocks(node, rc);
+    rc.getOut().noMoreTokens();
+    out.write("\n");
+    out.write("// export for Closure Compiler\n");
+    out.write("if (typeof window !== 'undefined') {\n");
+    out.write("  window['html4'] = html4;\n");
+    out.write("}\n");
+  }
+
+  /**
+   * The Blocks in the tree are used just as bundles of statements, so
+   * flatten them out.
+   */
+ private static void renderFlattenedBlocks(Statement node, RenderContext rc) {
+    if (node instanceof Block) {
+      for (Statement s : ((Block) node).children()) {
+        renderFlattenedBlocks(s, rc);
+        if (!s.isTerminal()) { rc.getOut().consume(";"); }
+      }
+    } else {
+      node.render(rc);
+    }
+  }

   public static class Builder implements BuildCommand {
public boolean build(List<File> inputs, List<File> deps, Map<String, Object> options,
@@ -526,39 +571,7 @@
       Writer out = new OutputStreamWriter(
           new FileOutputStream(output), Charsets.UTF_8.name());
       try {
-        String currentDate = "" + new Date();
-        if (currentDate.indexOf("*/") >= 0) {
- throw new SomethingWidgyHappenedError("Date should not contain '*/'");
-        }
-        out.write("// Copyright Google Inc.\n");
-        out.write("// Licensed under the Apache Licence Version 2.0\n");
-        out.write("// Autogenerated at " + currentDate + "\n");
-        out.write("// @overrides window\n");
-        out.write("// @provides html4\n");
-        Block node = generateJavascriptDefinitions(schema);
-        RenderContext rc = new RenderContext(node.makeRenderer(out, null))
-            .withPropertyNameQuotingMode(
-                PropertyNameQuotingMode.PRESERVE_QUOTES);
-        for (Statement s : node.children()) {
-          s.render(rc);
-          if (!s.isTerminal()) { rc.getOut().consume(";"); }
-        }
-        rc.getOut().noMoreTokens();
-        out.write("\n");
-        out.write("// exports for Closure Compiler\n");
-        out.write("html4['ATTRIBS'] = html4.ATTRIBS;\n");
-        out.write("html4['ELEMENTS'] = html4.ELEMENTS;\n");
-        out.write("html4['ELEMENT_DOM_INTERFACES'] = " +
-            "html4.ELEMENT_DOM_INTERFACES;\n");
-        out.write("html4['URIEFFECTS'] = html4.URIEFFECTS;\n");
-        out.write("html4['LOADERTYPES'] = html4.LOADERTYPES;\n");
-        out.write("html4['atype'] = html4.atype;\n");
-        out.write("html4['eflags'] = html4.eflags;\n");
-        out.write("html4['ltypes'] = html4.ltypes;\n");
-        out.write("html4['ueffects'] = html4.ueffects;\n");
-        out.write("if (typeof window !== 'undefined') {\n");
-        out.write("  window['html4'] = html4;\n");
-        out.write("}\n");
+        generateSourceText(schema, out);
       } finally {
         out.close();
       }
@@ -566,14 +579,13 @@
     }
   }

-  public static void main(String[] args) {
+  public static void main(String[] args) throws IOException {
     HtmlSchema schema = HtmlSchema.getDefault(new SimpleMessageQueue());
-    Block node = generateJavascriptDefinitions(schema);
- RenderContext rc = new RenderContext(node.makeRenderer(System.out, null));
-    for (Statement s : node.children()) {
-      s.render(rc);
-      if (!s.isTerminal()) { rc.getOut().consume(";"); }
+    Writer out = new OutputStreamWriter(System.out);
+    try {
+      generateSourceText(schema, out);
+    } finally {
+      out.close();
     }
-    rc.getOut().noMoreTokens();
   }
 }

Reply via email to