Author: dda
Date: 2008-02-27 14:07:56 -0800 (Wed, 27 Feb 2008)
New Revision: 8118

Modified:
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
   
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
   
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
Log:
Change 20080222-dda-o by [EMAIL PROTECTED] on 2008-02-22 21:31:39 EST
    in /Users/dda/laszlo/src/svn/openlaszlo/trunk-dep
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Add support for new dependency mechanism in script compiler

New Features: 

Bugs Fixed: LPP-5335 (partial)

Technical Reviewer: ptw (pending)
QA Reviewer: hminsky (pending)
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:
    Introduces a new function Compiler.dependenciesForExpression() taking
    a source expression e.g. "a.b.c + this.something.Fcn(1)" and
    producing a source expression representing the dependency, e.g.
      [a.b, "c"].concat(this.something.hasOwnProperty("$lsc$Fcn_dependencies") 
? (this.something cast Object).$lsc$Fcn_dependencies(this, this.something, 1) : 
[])

    This change does not functionally change *anything*, but it provides
    an API needed to switch over to having the tag compiler generate the 
    dependency functions.

    The significant changes are in ReferenceCollector, which keeps two
    implementations (old and new) for the moment.  It doesn't make sense
    to refactor them into a common codebase since the old implementation
    will go away after new dependencies are fully integrated.  The old 
implementation
    internal methods can be found in ReferenceCollector named as 
*_using_subfunction
    in reference to the original naming convention fcn() -> fcn.dependencies() .

    The new implementation uses naming fcn() -> $lsc$fcn_dependencies() as
    indicated in the example above.
    The implementation is conscious of the naming convention, since there
    may be calls to the dependency functions in the produced output.

    There is also a fix to the ParseTreePrinter so that it knows how to print
    'cast'.  This wasn't needed before to print final output from JS1, since
    casts were always removed.  Casts are generated in the dependency source
    so they will work with SWF9 - without it, the flex compile complains
    about references to nonexistant dependency functions.  Downcasting to
    Object makes the compiler *less* strict and accepting of any function name.
    The output from the simple dependency given above has been tested to
    compile with flex2 as a proof of concept.
    
    Also a small improvement to ReferenceGenerator to only create one 
Compiler.Parser object.

    This snippet added to NodeModel.java during testing (but not part of this 
change)
    shows how the new dependency function can be called:

        if (when.equals(WHEN_ALWAYS)) {
            System.out.println("CONSTRAINT: src = " + 
canonicalValue.toString());
            String dep = (new 
org.openlaszlo.sc.Compiler()).dependenciesForExpression(canonicalValue.toString());
            System.out.println("CONSTRAINT: dep = " + dep);
        }


Tests:
    regression: smokecheck,weather,lzpix (swf8/dhtml), runlzunit



Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java     
2008-02-27 20:53:04 UTC (rev 8117)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java     
2008-02-27 22:07:56 UTC (rev 8118)
@@ -380,6 +380,49 @@
     }
   }
 
+  /**
+   * @param source javascript source for a function (including function 
keyword, etc.)
+   * @param name name, will get name_dependencies as name of function
+   */
+  public String dependenciesForExpression(String estr) {
+    String fname = "$lsc$dependencies";
+    String source = "function " + fname + " () {" +
+      "\n#pragma 'constraintFunction'\n" +
+      "\n#pragma 'withThis'\n" +
+      // Use this.setAttribute so that the compiler
+      // will recognize it for inlining.
+      "this.setAttribute(\"x\", " +
+                    "\n#beginAttribute\n" + estr +
+                    "\n#endAttribute\n)}";
+
+    return dependenciesForFunction(source);
+  }
+
+  /**
+   * @param source javascript source for a function
+   */
+  private String dependenciesForFunction(String source) {
+    SimpleNode node = new Parser().parse(source);
+    // Expect ASTProgram -> ASTModifiedDefinition -> ASTFunctionDeclaration
+    SimpleNode fcn = node.get(0).get(0);
+    if (!(fcn instanceof ASTFunctionDeclaration))
+      throw new CompilerError("Internal error: bad AST for constraints");
+
+    ReferenceCollector dependencies = new 
ReferenceCollector(options.getBoolean(Compiler.COMPUTE_METAREFERENCES));
+
+    SimpleNode[] children = fcn.getChildren();
+    int stmtpos = (children.length - 1);
+    for (;stmtpos < children.length; stmtpos++) {
+      dependencies.visit(children[stmtpos]);
+    }
+    SimpleNode depExpr = dependencies.computeReferencesAsExpression();
+    String result = new ParseTreePrinter().visit(depExpr);
+    if (options.getBoolean(Compiler.PRINT_CONSTRAINTS)) {
+      System.out.println(result);
+    }
+    return result;
+  }
+
   //
   // Compiler Options
   //
@@ -849,6 +892,6 @@
 }
 
 /**
- * @copyright Copyright 2001-2007 Laszlo Systems, Inc.  All Rights
+ * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights
  * Reserved.  Use is subject to license terms.
  */

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
===================================================================
--- 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java 
    2008-02-27 20:53:04 UTC (rev 8117)
+++ 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java 
    2008-02-27 22:07:56 UTC (rev 8118)
@@ -375,6 +375,7 @@
     on.set(Ops.DELETE, "delete");
     on.set(Ops.VOID, "void");
     on.set(Ops.NEW, "new");
+    on.set(Ops.CAST, "cast");
     
     OperatorNames = (String[])on.toArray(OperatorNames);
   }

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
===================================================================
--- 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
   2008-02-27 20:53:04 UTC (rev 8117)
+++ 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
   2008-02-27 22:07:56 UTC (rev 8118)
@@ -27,6 +27,7 @@
   Set metareferences;
   Set metafunctions;
   String depth = "";
+  Compiler.Parser parser = new Compiler.Parser();
 
   public ReferenceCollector() {
     this(false);
@@ -64,9 +65,13 @@
     return s;
   }
 
+  // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+  //    'subfunction' naming (Class.f() and Class.f.dependencies())
+  //     does not work in SWF9.
+
   // f(args...) -> f["dependencies"](this, undefined, args...)
   // a.f(args...) -> f["dependencies"](this, a, args...)
-  private SimpleNode fsubst(SimpleNode node) {
+  private SimpleNode fsubst_using_subfunction(SimpleNode node) {
     SimpleNode fn = node.get(0);
     SimpleNode callee;
     if (fn instanceof ASTPropertyIdentifierReference) {
@@ -84,12 +89,66 @@
     map.put("_1", fn);
     map.put("_2", callee);
     map.put("_3", new Compiler.Splice(node.get(1).getChildren()));
-    // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
-    return (new 
Compiler.Parser()).substitute("_1.hasOwnProperty('dependencies') ? 
_1.dependencies(this, _2, _3) : []", map);
+    return parser.substitute("_1.hasOwnProperty('dependencies') ? 
_1.dependencies(this, _2, _3) : []", map);
   }
 
+  // callee.fn(args...) ->
+  //    callee.hasOwnProperty('$lsc$fn_dependencies') ?
+  //      (callee cast Object).$lsc$fn_dependencies(args...) : []
+  // If callee doesn't exist (i.e. original expression is just fn()),
+  // then 'this' is assumed for callee.  If we don't downcast the callee
+  // at the point of the call, on SWF9 we'd get compile errors
+  // when the dependency function doesn't exist.
+  // The cast is a no-op for runtimes that don't need them.
+  private SimpleNode fsubst(SimpleNode node) {
+    SimpleNode fn = node.get(0);
+    SimpleNode callee;
+    if (fn instanceof ASTPropertyIdentifierReference) {
+      callee = fn.get(0);
+      fn = fn.get(1);
+    } else {
+      callee = new ASTThisReference(0);
+    }
+    String depnm = "$lsc$" + ((ASTIdentifier)fn).getName() + "_dependencies";
+
+    // the function uses #pragma "warnUndefinedReferences=false"
+    // to avoid warnings for non-existent dependencies
+    Map map = new HashMap();
+    map.put("_1", callee);
+    map.put("_2", new Compiler.Splice(node.get(1).getChildren()));
+
+    return parser.substitute("_1.hasOwnProperty('" + depnm + "') ? (_1 cast 
Object)." + depnm + "(this, _1, _2) : []", map);
+  }
+
+  // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+  //    'subfunction' naming (Class.f() and Class.f.dependencies())
+  //     does not work in SWF9.
+
   // Concatenate references array with any results from dependeny
   // functions
+  private SimpleNode build_using_subfunction(Set references, Set functions) {
+    SimpleNode a = rsubst(references);
+    Map map = new HashMap();
+    Set added = new HashSet();
+    ParseTreePrinter ptp = new ParseTreePrinter();
+    for (Iterator i = functions.iterator(); i.hasNext(); ) {
+      SimpleNode n = (SimpleNode)i.next();
+      String s = ptp.visit(n);
+      // Eliminate redundant constraints
+      if (! added.contains(s)) {
+        added.add(s);
+        SimpleNode b = fsubst_using_subfunction(n);
+
+        map.put("_1", a);
+        map.put("_2", b);
+        a = parser.substitute("_1.concat(_2)", map);
+      }
+    }
+    return a;
+  }
+
+  // Concatenate references array with any results from dependeny
+  // functions
   private SimpleNode build(Set references, Set functions) {
     SimpleNode a = rsubst(references);
     Map map = new HashMap();
@@ -105,17 +164,30 @@
 
         map.put("_1", a);
         map.put("_2", b);
-        // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
-        a = (new Compiler.Parser()).substitute("_1.concat(_2)", map);
+        a = parser.substitute("_1.concat(_2)", map);
       }
     }
     return a;
   }
 
+  // TODO: [2006-02-22 dda] Do we want to keep computeMetaReferences?
+  // ptw says it's a failed experiment.  It's hard to test any
+  // new code that keeps it alive.
+
+  public SimpleNode computeReferencesAsExpression() {
+    return build(references, functions);
+  }
+
+  // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+  //    'subfunction' naming (Class.f() and Class.f.dependencies())
+  //     does not work in SWF9.
+  //     Migrate callers to new implementation in
+  //     computeReferencesAsExpression().
+
   public SimpleNode computeReferences(String name) {
     // Sanitize the name
     name = name.replace('#', '_').replace(' ', '_').replace('/', 
'_').replace('.', '_');
-    SimpleNode d = build(references, functions);
+    SimpleNode d = build_using_subfunction(references, functions);
     if (computeMetaReferences) {
       for (Iterator i = metareferences.iterator(); i.hasNext(); ) {
         SimpleNode r = (SimpleNode)i.next();
@@ -125,13 +197,12 @@
           metareferences.remove(r);
         }
       }
-      SimpleNode md = build(metareferences, metafunctions);
+      SimpleNode md = build_using_subfunction(metareferences, metafunctions);
       // store metadependencies as a property of deps
       Map map = new HashMap();
       map.put("_1", d);
       map.put("_2", md);
-      // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
-      return (new Compiler.Parser()).substitute(
+      return parser.substitute(
         // TODO: [2003-06-19 ptw] (krank) Have to use sanitized
         // name here, so that substitute does not try to name
         // the function "x"
@@ -144,8 +215,7 @@
     } else {
       Map map = new HashMap();
       map.put("_1", d);
-      // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
-      return (new Compiler.Parser()).substitute(
+      return parser.substitute(
         // TODO: [2003-06-19 ptw] (krank) Have to use sanitized
         // name here, so that substitute does not try to name
         // the function "x"


_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins

Reply via email to