Revision: 4745
Author:   erights
Date:     Mon Jan  2 04:40:07 2012
Log:      Fixed the expansion of completion values.

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

Modified:
 /trunk/experimental/src/com/google/caja/ses/expandProgramToExpr.js

=======================================
--- /trunk/experimental/src/com/google/caja/ses/expandProgramToExpr.js Tue Dec 27 23:22:53 2011 +++ /trunk/experimental/src/com/google/caja/ses/expandProgramToExpr.js Mon Jan 2 04:40:07 2012
@@ -23,7 +23,7 @@
  * <p>Serves as pseudo-code until we can run it. This section explains
  * what more is needed to turn this into running code.
  *
- * We express our translations using JavaScript <a href=
+ * <p>We express our translations using JavaScript <a href=
  * "http://wiki.ecmascript.org/doku.php?id=harmony:quasis";
  * >quasiliterals</a> and a hypothetical JavaScript quasi-parser named
  * "js". We additionally assume that the expression syntax {a, b} is
@@ -40,26 +40,26 @@
* "http://wiki.ecmascript.org/doku.php?id=strawman:object_initialiser_shorthand#discussion";
  * >object initializer discussion</a> section.
  *
- * Together, this means that (quasiParser`stuff${{varName}}stuff`) can
- * create an object that can be used as a pattern, placing the values
- * extracted from the specimen into varName, which must have already
- * been declared. As a further elaboration, we assume predicate
- * pattern functions that wrap such a literal
+ * <p>Together, this means that (quasiParser`stuff${{varName}}stuff`)
+ * can create an object that can be used as a pattern, placing the
+ * values extracted from the specimen into varName, which must have
+ * already been declared. As a further elaboration, we assume
+ * predicate pattern functions that wrap such a literal
  * (quasiParser`stuff${isThing({varName})}stuff`) and report whether
  * the proposed assignment meets it criteria. If not, that match
  * fails.
  *
- * Separately from the rules below, we also prohibit identifiers
+ * <p>Separately from the rules below, we also prohibit identifiers
  * ending in ___ (triple underbar) in the input, so that we may use
  * them in the output without fear of capture.
  *
- * The JavaScript quasiParser accepts one additional element besides
+ * <p>The JavaScript quasiParser accepts one additional element besides
  * JavaScript syntax and $ holes. In addition, when an "*", "+", or
  * "?" appears immediately to the right of a $ hole with no
  * intervening space, then it is taken as a quantifier on the binding
  * of the $ hole to consecutive AST elements.
  *
- * Besides the "js" quasi-parser, the following code depends on the
+ * <p>Besides the "js" quasi-parser, the following code depends on the
  * following helper functions. Depending on the concrete AST
  * representation chosen, perhaps some of these should instead be uses
  * of AST methods. Refactor as needed.<ul>
@@ -76,7 +76,7 @@
  * <li>makeAstLike        - like arg, with alternate children
  * </ul>
  *
- * The expanded code assumes bindings for<ul>
+ * <p>The expanded code assumes bindings for<ul>
  * <li>declareGlobal___
  * <li>defineGlobal___
  * <li>cleanErr___
@@ -88,7 +88,7 @@
  * license to translate by other means. This condition aborts the
  * overall translation.
  *
- * When translating a Source-SES script program, as might appear
+ * <p>When translating a Source-SES script program, as might appear
  * between script tags, declareGlobal___ and defineGlobal___ should
  * mutate the virtual global, enabling inter-module linkage. When
  * translating a Source-SES eval program, as might be passed to an
@@ -129,28 +129,12 @@
     * Translate a Source-SES Program production AST, as might appear
     * in Source-SES script or eval code, into a Target-SES Expression
     * production AST suitable for giving to cajaVM.compileExpr.
-    *
-    * This expander fixes the "Completion Value" anomaly of
-    * Target-SES, using the "completion value reform" semantics
-    * proposed for ES6.
     */
    expandProgramToExpr = function expandProgramToExpr(ast) {
-     if (!isProgram.test(ast)) { return null; }
-     var prog, expr;
-
-     if (js`${isStatementOrDecl({prog})}*
-            ${isExpr({expr})}`.test(ast)) {
-
+     if (isProgram.test(ast)) {
        return js`(function(global___) {
-                    ${expandAll(prog)}*
-                    return ${expand(expr)};
-                  }).call(this, this)`
-     }
-     if (js`${isStatementOrDecl({prog})}*`.test(ast)) {
-
-       return js`(function(global___) {
-                    ${expandAll(prog)}*
-                  }).call(this, this)`
+                   ${returnCompletion(ast)}
+                 }).call(this, this)`;
      }
      return null;
    }
@@ -179,8 +163,8 @@
      if (firstTokenName) {
        expander = byStartToken(firstTokenName);
        if (expander) {
-           result = expander(ast);
-           if (result) { return result; }
+         result = expander(ast);
+         if (result) { return result; }
        }
      }
      for (var i = 0, len = others.length; i++) {
@@ -194,7 +178,7 @@
    }

    /**
-    * This expander fixed the "Top Level Declarations" anomaly of
+    * This expander fixes the "Top Level Declarations" anomaly of
     * Target-SES.
     */
    function expandTopDecl(ast) {
@@ -285,4 +269,54 @@
      return null;
    }
    byStartToken.set('try', expandTryCatch);
+
+   /**
+    * Expand a Source-SES AST fragement occuring is a top
+    * level-context that could return a <a href=
+    * "http://wiki.ecmascript.org/doku.php?id=harmony:completion_reform";
+    * >completion value</a> and return a corresponding Target-SES
+    * fragment to appear at a similar location in a function body,
+    * where the expression that would compute the completion value is
+    * preceded by "return", so that this value is instead returned as
+    * the value of the enclosing function.
+    *
+    * <p>This expander fixes the "Completion Value" anomaly of
+    * Target-SES, using the <a href=
+    * "http://wiki.ecmascript.org/doku.php?id=harmony:completion_reform";
+    * >completion value reform</a> semantics proposed for ES6.
+    */
+       function returnCompletion(ast) {
+         var allButLast, last, expr, then, els, body;
+
+         if (js``.test(ast)) { return js``; }
+
+         if (js`${isStatementOrDecl({allButLast})}*
+                ${isStatementOrDecl({last})}`.test(ast)) {
+
+           return js`${expandAll(allButLast)}*
+                     ${returnCompletion(last)}`
+         if (js``.test(ast)) { return js``; }
+
+
+         if (js`${isExpr(expr);}.test(ast) {
+           return js`return ${expand(expr)};`;
+         }
+         if (js`if ($expr) $then $els`.test(ast)) {
+
+           return js`if (${expand(expr)})
+                         ${returnCompletion(then)}
+                         ${returnCompletion(els)}`;
+         }
+         if (js`while ($expr) $body`.test(ast)) {
+
+           return js`while (${expand($expr))} ${returnCompletion(body)}`;
+         }
+
+         // TODO(erights): If any other statements can produce
+         // completion values according to the completion value reform
+         // semantics, place them here.
+
+         return expand(ast);
+       }
+
  })();

Reply via email to