Author: ptw
Date: 2007-08-17 16:26:58 -0700 (Fri, 17 Aug 2007)
New Revision: 6134

Modified:
   openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/compiler/Class.lzs
   openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/core/LzDefs.lzs
   
openlaszlo/branches/wafflecone/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
   
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
   
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
   
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptCompressor.java
   
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
Log:
Change 20070817-ptw-3 by [EMAIL PROTECTED] on 2007-08-17 07:12:53 EDT
    in /Users/ptw/OpenLaszlo/wafflecone
    for http://svn.openlaszlo.org/openlaszlo/branches/wafflecone

Summary: Remove `make` trampoline from Class system

Bugs Fixed:
LPP-1605 'ctor precedence is wrong'
LPP-4365 'Adding prototype functions to builtin objects a bit broken'
LPP-4513 'Compiler Improvements to address performance'

Technical Reviewer: max (Message-ID: <[EMAIL PROTECTED]>)
QA Reviewer: hminsky (pending)

Details:
    LzDefs: Rework LzInheritedHash to not require .make.

    Class: Rework contstructors to call .initialize, .make retained
    for backwards-compatibility.  Split out class validation code.

    Compiler: Remove passThroughNodes before dispatching.  Print new
    expressions with correct associativity.

    JavascriptGenerator, JavascriptCompressor, CodeGenerator: Remove
    translation of new to .make

    Parser.jjt: Learn how to correctly parse a `new` expressions and
    maintain associativity.

Tests:
    smokecheck in swf7, swf8, dhtml



Modified: openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/compiler/Class.lzs
===================================================================
--- openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/compiler/Class.lzs   
2007-08-17 22:58:20 UTC (rev 6133)
+++ openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/compiler/Class.lzs   
2007-08-17 23:26:58 UTC (rev 6134)
@@ -20,8 +20,14 @@
   *
   * @access private
   * @bootstrap true
+  *
+  * @devnote This is the first class constructor.  Constructors for
+  * all other classes are created by Class.make (below).
   */
-var Instance = function () { this.constructor = arguments.callee };
+var Instance = function constructor () {
+  this.constructor = arguments.callee
+  this.initialize.apply(this, arguments);
+};
 Instance.prototype.constructor = Instance; 
 Instance.prototype.__initialized = false;
 Instance.classname = 'Instance';
@@ -71,7 +77,7 @@
           // Delay 'til runtime so classes can adjust their name to be
           // their tag name
           value._dbg_owner = this;
-          value._dbg_typename = function () {
+          value._dbg_typename = function _dbg_typename () {
             var o = this._dbg_owner;
             var t = o._dbg_typename;
             // Prototypes have their own typename, instances should
@@ -139,6 +145,8 @@
   * Default method does nothing
   *
   * @access private
+  *
+  * @devnote The call to the default method is optimized away in class 
constructors
   */
 Instance.prototype.addProperty('initialize', function initialize () {});
 
@@ -173,74 +181,89 @@
   * Make a new instance of a class.
   *
   * @access private
+  *
+  * @devnote This is just for coherence with the Class interface.
+  * Normally new instances will be created by `new _class_`.
   */
 Instance.make = function make () {
-  // Scaffolding until the LFC is rewritten to use NewClass
-  var prototype = this.prototype;
-  do {
-  var constructor = prototype.constructor;
-  if (! prototype.__initialized) {
-    // Debug.debug('Initializing', this.classname);
-    for (var k in prototype) {
-      if (prototype.hasOwnProperty(k) && k != 'constructor') {
-        // Debug.debug(k);
-        var value = prototype[k];
-        // Cf., Instance.addProperty
-        if (value instanceof Function) {
-          if (value.hasOwnProperty('superclasses')) {
-            var os = value.superclasses, found = false;
-            for (var i = os.length - 1; i >= 0; i--) {
-              if (os[i] === constructor) {
-                found = true;
-                break;
+  // Should not be called in the new world...
+  if ($debug) {
+    Debug.warn("`%w.%s` is deprecated.  Use `new %w` instead.", this, 
arguments.callee, this);
+  }
+  {
+    #pragma "passThrough=true"
+    if (arguments.length > 0) {
+      // We have to work hard to break a conventional constructor into a
+      // constructor and initializer when there are args, because
+      // Javascript does not support apply of new.
+      var constructor = this;
+      function xtor () { this.constructor = constructor; };
+      xtor.prototype = constructor.prototype;
+      var o = new xtor();
+      constructor.apply(o, arguments);
+      return o;
+    }
+    return new this();
+  }
+};
+
+if ($debug) {
+  Instance.make._dbg_typename = 'Instance static function';
+};
+
+if ($debug) {
+  Instance.prototype.addProperty('validateClassStructure', function 
validateClassStructure () {
+    // Verifies that superclass links for nextMethod are correct
+    var prototype = this.constructor.prototype;
+    do {
+      var constructor = prototype.constructor;
+      if (! prototype.__initialized) {
+        // Debug.debug('Validating', constructor);
+        for (var k in prototype) {
+          if (prototype.hasOwnProperty(k) && k != 'constructor') {
+            // Debug.debug(k);
+            var value = prototype[k];
+            // Cf., Instance.addProperty
+            if (value instanceof Function) {
+              if (value.hasOwnProperty('superclasses')) {
+                var os = value.superclasses, found = false;
+                for (var i = os.length - 1; i >= 0; i--) {
+                  if (os[i] === constructor) {
+                    found = true;
+                    break;
+                  }
+                }
+                if (! found) {
+                  value.superclasses.push(constructor);
+                  Debug.error('Invalid class structure [3+]: Use `addProperty` 
to create %w.%s', this, k);
+                }
+              } else if (value.hasOwnProperty('superclass')) {
+                var o = value.superclass;
+                if (o !== constructor) {
+                  delete value.superclass;
+                  value.superclasses = [ o, constructor ];
+                  Debug.error('Invalid class structure [2]: Use `addProperty` 
to create %w.%s', this, k);
+                }
+              } else {
+                value.superclass = constructor;
+                Debug.error('Invalid class structure [1]: Use `addProperty` to 
create %w.%s', this, k);
               }
             }
-            if (! found) {
-              value.superclasses.push(constructor);
-              if ($debug) {
-                Debug.debug('Shim %s.%s [3+]', this, k)
-              }
-            }
-          } else if (value.hasOwnProperty('superclass')) {
-            var o = value.superclass;
-            if (o !== constructor) {
-              delete value.superclass;
-              value.superclasses = [ o, constructor ];
-              if ($debug) {
-                Debug.debug('Shim %s.%s [2]', this, k);
-              }
-            }
-          } else {
-            value.superclass = constructor;
-            if ($debug) {
-              Debug.debug('Shim %s.%s [1]', this, k);
-            }
           }
         }
+        prototype.__initialized = true;
       }
-    }
-    //    Debug.debug('[2] Initializing', this.classname);
-    prototype.__initialized = true;
-  }
-  prototype = constructor.prototype;
-  } while (constructor !== Instance);
+      prototype = constructor.prototype;
+    } while (constructor !== Instance);
+    });
+};
 
-  #pragma "passThrough=true"
-  var i = new this();
-  i.initialize.apply(i, arguments);
-  return i;
-}
-
-if ($debug) {
-  Instance.make._dbg_typename = 'Instance static function';
-}
-
 /**
   * Bootstrap Class class
   * @todo [2006-05-03 ptw] Rename to Class when LFC has been converted
   */
 var Class = {
-  prototype: Instance.make(),
+  prototype: new Instance(),
   // Add a method to a class by adding it to the class's prototype
   addProperty: function addProperty (name, value) {
     var proto = this.prototype;
@@ -275,7 +298,7 @@
     if ($debug) {
       if (value instanceof Function && (! value._dbg_typename)) {
         value._dbg_owner = this;
-        value._dbg_typename = function () { return this._dbg_owner._dbg_name + 
' static function'};
+        value._dbg_typename = function _dbg_typename () { return 
this._dbg_owner._dbg_name + ' static function'};
       }
     }
   },
@@ -289,7 +312,19 @@
   // staticProperties:Object is a hash of the inital class properties;
   make: function make (classname, traitsAndSuperclass, instanceProperties, 
staticProperties) {
     // The constructor notes itself in every instance
-    var nc = function () { this.constructor = arguments.callee; };
+    var nc = function constructor () {
+      this.constructor = arguments.callee;
+      if ($debug) {
+        // Must come after the constructor is installed
+//         Debug.debug("Validate", this, this.validateClassStructure);
+        this.validateClassStructure();
+      }
+      // Call the initializer if it is not the default
+      if (this.initialize !== Instance.prototype.initialize) {
+        // Debug.debug('Initializing', this);
+        this.initialize.apply(this, arguments);
+      }
+    };
     nc.constructor = this;
     nc.classname = classname;
     if ($debug) {
@@ -328,8 +363,12 @@
     // The prototype is an instance of our super, which causes us to
     // inherit our super's instanceProperties
     {
+      // This has to be constructed carefully, so as _not_ to run the
+      // class instance initializer
+      var xtor = function prototype () { this.constructor = superclass; };
+      xtor.prototype = superclass.prototype;
       #pragma "passThrough=true"
-      var prototype = new superclass; // --- superclass.make();
+      var prototype = new xtor(); // --- superclass.make();
     }
     // Create any trait interstitials, following the pattern above
     if (traitsAndSuperclass instanceof Array) {
@@ -379,7 +418,7 @@
 
 /** Bootstrap Trait class */
 var Trait = {
-  prototype: Instance.make(),
+  prototype: new Instance(),
   allTraits: {},
   _dbg_typename: Class._dbg_name,
   _dbg_name: 'Trait',
@@ -394,7 +433,7 @@
       t.addProperty.apply(t, arguments);
     }
     if ($debug) {
-      if (value instanceof Function) {
+      if (value instanceof Function && (! value._dbg_typename)) {
         value._dbg_typename = this._dbg_name + ' function';
       }
     }
@@ -402,7 +441,7 @@
   addStaticProperty: function addStaticProperty (name, value) {
     this[name] = value;
     if ($debug) {
-      if (value instanceof Function) {
+      if (value instanceof Function && (! value._dbg_typename)) {
         value._dbg_typename = this._dbg_name + ' static function';
       }
     }
@@ -437,7 +476,7 @@
       superclassInstance.addProperty.call(superclassInstance, name, 
prototype[name]);
     }
     // Make the interstitial
-    var xtor = function () { this.constructor = arguments.callee; };
+    var xtor = function interstitial () { this.constructor = arguments.callee; 
};
     xtor.prototype = superclassInstance;
     // The trait's initialize method will run in Class.make (in the
     // proper order).
@@ -449,8 +488,10 @@
     // Unique name must identify superclass chain, punctuation is
     // added for debugging
     xtor.classname = mash;
-    xtor._dbg_typename = 'Interstitial Constructor';
-    xtor._dbg_name = xtor.classname;
+    if ($debug) {
+      xtor._dbg_typename = 'Interstitial Constructor';
+      xtor._dbg_name = xtor.classname;
+    }
     #pragma "passThrough=true"
     var t = new xtor();
     // Remember

Modified: openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/core/LzDefs.lzs
===================================================================
--- openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/core/LzDefs.lzs      
2007-08-17 22:58:20 UTC (rev 6133)
+++ openlaszlo/branches/wafflecone/WEB-INF/lps/lfc/core/LzDefs.lzs      
2007-08-17 23:26:58 UTC (rev 6134)
@@ -69,18 +69,21 @@
   * Used to efficiently clone hashtables using Object's
   * N.B. these tables incorrectly will appear to have entries for all
   * the properties of Object.prototype.  To avoid this (but pay the
-  * of a slower implementation, use LzDictionary).
+  * overhead of a slower implementation, use LzDictionary).
   * @access private
   */
-var LzInheritedHash = {
-  make: function make (parent) {
-#pragma "passThrough=true"
-    if (parent) {
-      function xtor() {};
+function LzInheritedHash (parent)  {
+  var constructor = arguments.callee
+  if (! parent) {
+    this.constructor = constructor;
+  } else {
+    if ($as2) {
+      this.__proto__ = parent;
+    } else {
+      function xtor() { this.constructor = constructor; };
       xtor.prototype = parent;
       return new xtor();
     }
-    return new Object;
   }
 }
 

Modified: 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
===================================================================
--- 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
       2007-08-17 22:58:20 UTC (rev 6133)
+++ 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
       2007-08-17 23:26:58 UTC (rev 6134)
@@ -384,12 +384,11 @@
 
 void PrimarySuffix() #void : {}
 {
-    ((Arguments()) #FunctionCallParameters)
-|   (("[" Expression() "]") #PropertyValueReference)
+    (("[" Expression() "]") #PropertyValueReference)
 |   (("." IdentifierOrKeyword()) #PropertyIdentifierReference)
 }
 
-void Arguments() # void: {}
+void Arguments() #FunctionCallParameters: {}
 {
     "(" [ArgumentList()] ")"
 }
@@ -418,9 +417,23 @@
     (Identifier() | StringLiteral() | NumericLiteral()) ":" 
AssignmentExpression()
 }
 
+// A member expression is any number of '.' and '[' expressions
+void MemberExpression() #CallExpression(>1) : {}
+{
+  PrimaryExpression() ((LOOKAHEAD("." | "[") PrimarySuffix())*)
+}
+
+// A new expression ends with the first argument list
+void NewExpression() #NewExpression : {}
+{
+  "new" MemberExpression()  ([LOOKAHEAD("(") Arguments()] 
#EmptyExpression(jjtree.nodeArity()==0))
+}
+
+// Whereas a call expression allows intermingled '.', '[', and '(' expressions
 void CallExpression() #CallExpression(>1) : {}
 {
-  PrimaryExpression() ((PrimarySuffix())*)
+  PrimaryExpression() (PrimarySuffix() | Arguments())*
+  | NewExpression() (PrimarySuffix() | Arguments())*
   | SuperCallExpression()
 }
 
@@ -430,17 +443,9 @@
           ([ LOOKAHEAD("." Identifier(), { "apply".equals(getToken(2).image) 
|| "call".equals(getToken(2).image) })
             "." Identifier()
            ] #EmptyExpression(jjtree.nodeArity()==0))
-          (Arguments() #FunctionCallParameters)
+          Arguments()
 }
 
-
-void LeftHandSideExpression() #NewExpression(>1) : {}
-{
-//   LOOKAHEAD(3)
-   (("new" CallExpression()) #NewExpression) | CallExpression()
-//|  ("new" "super" (Arguments() #FunctionCallParameters))
-}
-
 void PostfixOp() #Operator : {Token t;}
 {
   ("++" | "--")
@@ -449,7 +454,7 @@
 
 void PostfixExpression() #PostfixExpression(>1) : {}
 {
-    LeftHandSideExpression() [PostfixOp()]
+    CallExpression() [PostfixOp()]
 }
 
 void UnaryOp() #Operator : {Token t;}

Modified: 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
===================================================================
--- 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
  2007-08-17 22:58:20 UTC (rev 6133)
+++ 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
  2007-08-17 23:26:58 UTC (rev 6134)
@@ -2048,40 +2048,20 @@
 
   public boolean visitNewExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children) {
     SimpleNode ref = children[0];
-    SimpleNode[] args = new SimpleNode[0];
-    if (ref instanceof ASTCallExpression) {
-      SimpleNode[] cn = ref.getChildren();
-      ref = cn[0];
-      args = cn[1].getChildren();
-    }
-    boolean primitive = false;
-    if (ref instanceof ASTIdentifier) {
-      String name = ((ASTIdentifier)ref).getName();
-      primitive = "Object".equals(name) || "Array".equals(name) || 
"String".equals(name) ||
-        "Boolean".equals(name) || "Number".equals(name) || "Date".equals(name) 
||
-        "Function".equals(name) || "RegExp".equals(name) || 
"Error".equals(name);
-    }
-    if (primitive || options.getBoolean("passThrough")) {
-      visitCallParameters(node, isReferenced, args);
-      boolean isref = translateReferenceForCall(ref, true, node);
-      if (isref) {
-        if (ref instanceof ASTPropertyIdentifierReference ||
-            ref instanceof ASTPropertyValueReference) {
-          collector.emit(Instructions.NewMethod);
-        } else {
-          collector.emit(Instructions.NEW);
-        }
-      } else {
-        // This is how you invoke a function value
-        collector.push(Values.Undefined);
+    SimpleNode[] args = children[1].getChildren();
+    visitCallParameters(node, isReferenced, args);
+    boolean isref = translateReferenceForCall(ref, true, node);
+    if (isref) {
+      if (ref instanceof ASTPropertyIdentifierReference ||
+          ref instanceof ASTPropertyValueReference) {
         collector.emit(Instructions.NewMethod);
+      } else {
+        collector.emit(Instructions.NEW);
       }
     } else {
-      Map map = new HashMap();
-      map.put("_1", ref);
-      map.put("_2", new Compiler.Splice(args));
-      SimpleNode n = (new Compiler.Parser()).substitute("_1.make(_2)", map);
-      visitCallExpression(n, isReferenced, n.getChildren());
+      // This is how you invoke a function value
+      collector.push(Values.Undefined);
+      collector.emit(Instructions.NewMethod);
     }
     return false;
   }

Modified: 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
===================================================================
--- 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
       2007-08-17 22:58:20 UTC (rev 6133)
+++ 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
       2007-08-17 23:26:58 UTC (rev 6134)
@@ -607,7 +607,7 @@
           SimpleNode prop = node.get(1);
           assert ((prop instanceof ASTPropertyIdentifierReference ||
                    prop instanceof ASTPropertyValueReference) &&
-                  prop.size() > 0 ): prop;
+                  prop.size() > 0 ): (new 
Compiler.ParseTreePrinter()).visit(prop);
           int size = node.size();
           SimpleNode children[] = new SimpleNode[2];
           children[0] = node.get(0);
@@ -854,9 +854,14 @@
       }
 
       int size = node.size();
+      SimpleNode[] childnodes = node.getChildren();
       String[] children = new String[size];
       for (int i = 0; i < size; i++) {
-        children[i] = visit(node.get(i)) ;
+        SimpleNode n = childnodes[i];
+        if (n instanceof PassThroughNode) {
+          n = childnodes[i] = ((PassThroughNode)n).realNode;
+        }
+        children[i] = visit(n) ;
       }
 
       Class nt = node.getClass();
@@ -1133,12 +1138,10 @@
       return defaultVisitor(node, children);
     }
     public String visitNewExpression(SimpleNode node, String[] children) {
-      // Associativity makes these parens superfluous
-//       int thisPrec = prec(Ops.NEW, true);
-//       SimpleNode c = node.get(0);
-//       children[0] = maybeAddParens(thisPrec, c, children[0]);
-      // Kludge for (new Foo).whatever
-      return "(new " + children[0] + ")";
+      int thisPrec = prec(Ops.NEW, true);
+      SimpleNode c = node.get(0);
+      children[0] = maybeAddParens(thisPrec, c, children[0]);
+      return "new " + children[0] + "(" + children[1] + ")";
     }
     public String visitPragmaDirective(SimpleNode node, String[] children) {
       return "#pragma " + children[0];

Modified: 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptCompressor.java
===================================================================
--- 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptCompressor.java
   2007-08-17 22:58:20 UTC (rev 6133)
+++ 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptCompressor.java
   2007-08-17 23:26:58 UTC (rev 6134)
@@ -45,15 +45,6 @@
     return node;
   }
 
-  // Don't transform new calls for compression
-  public SimpleNode visitNewExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children) {
-    for (int i = 0, len = children.length; i < len; i++) {
-      SimpleNode child = children[i];
-      children[i] = visitExpression(child, isReferenced);
-    }
-    return node;
-  }
-
 }
 
 /**

Modified: 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
===================================================================
--- 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
    2007-08-17 22:58:20 UTC (rev 6133)
+++ 
openlaszlo/branches/wafflecone/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
    2007-08-17 23:26:58 UTC (rev 6134)
@@ -1457,29 +1457,10 @@
   }
 
   public SimpleNode visitNewExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children) {
-    SimpleNode ref = children[0];
-    SimpleNode[] args = new SimpleNode[0];
-    if (ref instanceof ASTCallExpression) {
-      SimpleNode[] cn = ref.getChildren();
-      ref = cn[0];
-      args = cn[1].getChildren();
+    for (int i = 0, len = children.length; i < len; i++) {
+      SimpleNode child = children[i];
+      children[i] = visitExpression(child, isReferenced);
     }
-    boolean primitive = false;
-    if (ref instanceof ASTIdentifier) {
-      String name = ((ASTIdentifier)ref).getName();
-      primitive = "Object".equals(name) || "Array".equals(name) || 
"String".equals(name) ||
-        "Boolean".equals(name) || "Number".equals(name) || "Date".equals(name) 
||
-        "Function".equals(name) || "RegExp".equals(name) || 
"Error".equals(name);
-    }
-    if (primitive || options.getBoolean("passThrough")) {
-      children[0] = visitExpression(children[0]);
-    } else {
-      Map map = new HashMap();
-      map.put("_1", ref);
-      map.put("_2", new Compiler.Splice(args));
-      SimpleNode n = (new Compiler.Parser()).substitute("_1.make(_2)", map);
-      node = visitExpression(n, isReferenced);
-    }
     return node;
   }
 


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

Reply via email to