Author: ptw
Date: 2008-01-08 06:07:37 -0800 (Tue, 08 Jan 2008)
New Revision: 7763

Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/compiler/Class.lzs
   openlaszlo/trunk/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ASTVisitor.java
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
   
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
   
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
   openlaszlo/trunk/test/lztest/lztest-class-impl.lzx
Log:
Change 20080107-ptw-n by [EMAIL PROTECTED] on 2008-01-07 15:41:52 EST
    in /Users/ptw/OpenLaszlo/ringding-2
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Implement `is` operator

Bugs Fixed:
LPP-3632 'Implement `is` operator'

Technical Reviewer: [EMAIL PROTECTED] (pending)
QA Reviewer: [EMAIL PROTECTED] (pending)
Doc Reviewer: [EMAIL PROTECTED] (pending)

Documentation:
We now implement the ECMAScript 4 `is` operator

Details:
    lztest-class-impl: Use modern syntax, verify that `is` is
    equivalent to `instanceof` and works properly for mixins.

    Class: add runtime support for `is` operator on mixins

    JavascriptGenerator, CodeGenerator, ParseTreePrinter, Parser:  Add
    support for `is` operator, which in JS1 runtimes is approximated
    as:  a is b => b['$lzsc$isa'] ? b.$lzsc$isa(a) : (a instanceof b),
    relying on the runtime support in Class for $lzsc$isa.

    ASTVisitor: remove the unused visitBinaryExpression

Tests:
    Amended class-impl test to test that `is` is equivalent to
    `instanceof` for classes and works properly for mixins.



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/compiler/Class.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/compiler/Class.lzs 2008-01-08 06:00:07 UTC 
(rev 7762)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/compiler/Class.lzs 2008-01-08 14:07:37 UTC 
(rev 7763)
@@ -472,6 +472,16 @@
     impls[mash] = t;
     return t;
   },
+  // Implements `is` operator for traits
+  $lzsc$isa: function $lzsc$isa (obj) {
+    var impls = this.implementations;
+    for (var mash in impls) {
+      if (obj instanceof impls[mash].constructor) {
+        return true;
+      }
+      return false;
+    }
+  },
   // How to make a Trait
   make: function make (classname, superTrait, instanceProperties, 
staticProperties) {
     var nt = {
@@ -487,6 +497,7 @@
     this.addStaticProperty.call(nt, 'addStaticProperty', 
this.addStaticProperty);
     nt.addStaticProperty('addProperty', this.addProperty);
     nt.addStaticProperty('makeInterstitial', this.makeInterstitial);
+    nt.addStaticProperty('$lzsc$isa', this.$lzsc$isa);
     // Install the staticProperties
     if (staticProperties) {
       for (var i = staticProperties.length - 1; i >= 1; i -= 2) {

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt     
2008-01-08 06:00:07 UTC (rev 7762)
+++ openlaszlo/trunk/WEB-INF/lps/server/sc/src/org/openlaszlo/sc/Parser.jjt     
2008-01-08 14:07:37 UTC (rev 7763)
@@ -157,6 +157,7 @@
 | < IF: "if" >
 | < IN: "in" >
 | < INSTANCEOF: "instanceof" >
+| < IS: "is" >
 | < NEW: "new" >
 | < RETURN: "return" >
 | < SWITCH: "switch" >
@@ -364,6 +365,7 @@
   | t=<STATIC>
   | t=<OVERRIDE>
   | t=<DYNAMIC>
+  | t=<IS>
   )
     {return t;}
 }
@@ -538,7 +540,7 @@
 
 void RelOp() #Operator : {Token t;}
 {
-  ("<" | ">" | "<=" | ">=" | "instanceof" | LOOKAHEAD({getAllowIn()}) "in")
+  ("<" | ">" | "<=" | ">=" | "instanceof" | "is" | LOOKAHEAD({getAllowIn()}) 
"in")
     {jjtThis.setOperator(getToken(0).kind);}
 }
 

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ASTVisitor.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ASTVisitor.java   
2008-01-08 06:00:07 UTC (rev 7762)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ASTVisitor.java   
2008-01-08 14:07:37 UTC (rev 7763)
@@ -33,7 +33,6 @@
 
   SimpleNode visitArrayLiteral(SimpleNode node, boolean isReferenced, 
SimpleNode[] children);
   SimpleNode visitAssignmentExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children);
-  SimpleNode visitBinaryExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children);
   SimpleNode visitBinaryExpressionSequence(SimpleNode node, boolean 
isReferenced, SimpleNode[] children);
   SimpleNode visitCallExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children);
   SimpleNode visitConditionalExpression(SimpleNode node, boolean isReferenced, 
SimpleNode[] children);
@@ -75,7 +74,7 @@
 }
 
 /**
- * @copyright Copyright 2006-2007 Laszlo Systems, Inc.  All Rights
+ * @copyright Copyright 2006-2008 Laszlo Systems, Inc.  All Rights
  * Reserved.  Use is subject to license terms.
  */
 

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java
===================================================================
--- 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java    
    2008-01-08 06:00:07 UTC (rev 7762)
+++ 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CodeGenerator.java    
    2008-01-08 14:07:37 UTC (rev 7763)
@@ -248,7 +248,7 @@
   void report(String reportMethod, SimpleNode node, Object message) {
     collector.push(message);
     collector.push(node.beginLine);
-    collector.push(node.filename);
+    collector.push(node.filename != null ? node.filename : "unknown");
     collector.push(3);
     collector.push(reportMethod);
     collector.emit(Instructions.CallFunction);
@@ -261,7 +261,7 @@
     assert Instructions.DUP.equals(inst);
     collector.push(message);
     collector.push(node.beginLine);
-    collector.push(node.filename);
+    collector.push(node.filename != null ? node.filename : "unknown");
     collector.push(4);
     collector.push(reportMethod);
     collector.emit(Instructions.CallFunction);
@@ -272,7 +272,7 @@
   // when called, otherwise expects the function object.
   // TODO: [2006-01-04 ptw] Rewrite as a source transform
   void checkUndefinedFunction(SimpleNode node, String reference) {
-    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
       String label = newLabel(node);
       collector.emit(Instructions.DUP);                // ref ref
       // Get the value of a function reference
@@ -297,7 +297,7 @@
   // left on the stack.
   // TODO: [2006-01-04 ptw] Rewrite as a source transform
   void checkUndefinedMethod(SimpleNode node, String methodName) {
-    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
       // Check that object is not undefined
       String isUndefined = newLabel(node); // stack: object
       collector.emit(Instructions.DUP); // stack: object, object
@@ -1595,19 +1595,31 @@
     return translateBinaryExpression(node, isReferenced, (ASTOperator)op, a, 
b);
   }
 
-  public SimpleNode visitBinaryExpression(SimpleNode node, boolean 
isReferenced, SimpleNode[] children) {
-    SimpleNode op = children[0];
-    SimpleNode a = children[1];
-    SimpleNode b = children[2];
-    return translateBinaryExpression(node, isReferenced, (ASTOperator)op, a, 
b);
-  }
-
   SimpleNode translateBinaryExpression(SimpleNode node, boolean isReferenced, 
ASTOperator op, SimpleNode a, SimpleNode b) {
     visitExpression(a);
     visitExpression(b);
-    Instruction[] instrs = (Instruction[])BinopInstrs.get(op.getOperator());
-    for (int i = 0, len = instrs.length; i < len; i++) {
-      collector.emit(instrs[i]);
+    if (ParserConstants.IS ==  ((ASTOperator)op).getOperator()) {
+      // Approximate a is b as b['$lzsc$isa'] ? b.$lzsc$isa(a) : (a
+      // instanceof b)
+      ArrayList code = new ArrayList();
+      code.add(Instructions.DUP); // a b b
+      code.add(Instructions.PUSH.make("$lzsc$isa"));
+      code.add(Instructions.GetMember);   // a b b.$lzsc$isa
+      code.add(Instructions.BranchIfTrue.make(1)); // a b
+      code.add(Instructions.InstanceOf);           // (a instanceof b)
+      code.add(Instructions.BRANCH.make(2));
+      code.add(new Integer(1));             // a b
+      code.add(Instructions.PUSH.make(1));  // a b 1
+      code.add(Instructions.SWAP);          // a 1 b
+      code.add(Instructions.PUSH.make("$lzsc$isa")); // a 1 b '$lzsc$isa'
+      code.add(Instructions.CallMethod);             // b.$lzsc$isa(a)
+      code.add(new Integer(2));
+      translateControlStructure(node, code.toArray());
+    } else {
+      Instruction[] instrs = (Instruction[])BinopInstrs.get(op.getOperator());
+      for (int i = 0, len = instrs.length; i < len; i++) {
+        collector.emit(instrs[i]);
+      }
     }
     return node;
   }
@@ -2276,7 +2288,7 @@
   //                          fname, lineno, propertyName);
         collector.push(message);
         collector.push(node.beginLine);
-        collector.push(node.filename);
+        collector.push(node.filename != null ? node.filename : "unknown");
         collector.push(3);
         collector.push(reportMethod);
         collector.emit(Instructions.CallFunction);
@@ -2340,7 +2352,7 @@
     // property reference.  Expects the object to be at the top of stack
     // when called.
     protected void checkUndefinedObjectProperty(String propertyName) {
-      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
         String label = translator.newLabel(node);
         collector.emit(Instructions.DUP);
         collector.emit(Instructions.TypeOf);
@@ -2359,7 +2371,7 @@
     // too, hence the '==undefined' test.  Expects the object member to
     // be at the top of stack when called.
     protected void checkUndefinedPropertySelector(String propertyName) {
-      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
         String label = translator.newLabel(node);
         collector.emit(Instructions.DUP); // s s
         collector.push(Values.Undefined); // s s UNDEF
@@ -2375,7 +2387,7 @@
     // Expects the object member to be at the top of stack when
     // called.
     protected void checkUndefinedProperty(String propertyName) {
-      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
         String label = translator.newLabel(node);
         collector.emit(Instructions.DUP);
         collector.emit(Instructions.TypeOf);
@@ -2447,7 +2459,7 @@
     // Expects the value of the variable to be at the top of stack when
     // called.
     private void checkUndefinedVariable(SimpleNode node, String variableName) {
-      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && 
node.filename != null) {
+      if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
         String label = translator.newLabel(node);
         collector.emit(Instructions.DUP);
         collector.emit(Instructions.TypeOf);
@@ -2645,7 +2657,7 @@
 }
 
 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
-* Copyright 2001-2007 Laszlo Systems, Inc.  All Rights Reserved.              *
+* Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
 * Use is subject to license terms.                                            *
 * J_LZ_COPYRIGHT_END *********************************************************/
 

Modified: 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
===================================================================
--- 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
  2008-01-08 06:00:07 UTC (rev 7762)
+++ 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/JavascriptGenerator.java
  2008-01-08 14:07:37 UTC (rev 7763)
@@ -144,7 +144,7 @@
   // when called, otherwise expects the function object.
   // TODO: [2006-01-04 ptw] Rewrite as a source transform
   SimpleNode checkUndefinedFunction(SimpleNode node, JavascriptReference 
reference) {
-    if (options.getBoolean(Compiler.DEBUG) && 
options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && node.filename != 
null) {
+    if (options.getBoolean(Compiler.DEBUG) && 
options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
       return parseFragment(
         "typeof " + reference.get() + " != 'function' ? " + 
         report("$reportNotFunction", node, reference.get()) + " : " +
@@ -156,7 +156,7 @@
   // Emits code to check that an object method is defined.  Does a trial
   // fetch of methodName to verify that it is a function.
   SimpleNode checkUndefinedMethod(SimpleNode node, JavascriptReference 
reference, String methodName) {
-    if (options.getBoolean(Compiler.DEBUG) && 
options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES) && node.filename != 
null) {
+    if (options.getBoolean(Compiler.DEBUG) && 
options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)) {
       String o = newTemp();
       String om = newTemp();
       return parseFragment(
@@ -987,20 +987,31 @@
     SimpleNode a = children[0];
     SimpleNode op = children[1];
     SimpleNode b = children[2];
+    if (ParserConstants.IS ==  ((ASTOperator)op).getOperator()) {
+      // Approximate a is b as b['$lzsc$isa'] ? b.$lzsc$isa(a) : (a
+      // instanceof b)
+      Map map = new HashMap();
+      map.put("_1", a);
+      map.put("_2", b);
+      String pattern;
+      if ((a instanceof ASTIdentifier ||
+           a instanceof ASTPropertyValueReference ||
+           a instanceof ASTPropertyIdentifierReference) &&
+          (b instanceof ASTIdentifier ||
+           b instanceof ASTPropertyValueReference ||
+           b instanceof ASTPropertyIdentifierReference)) {
+        pattern = "(_2['$lzsc$isa'] ? _2.$lzsc$isa(_1) : (_1 instanceof _2))";
+      } else {
+        pattern = "(function (a, b) {return b['$lzsc$isa'] ? b.$lzsc$isa(a) : 
(a instanceof b)})(_1, _2))";
+      }
+      SimpleNode n = (new Compiler.Parser()).substitute(pattern, map);
+      return visitExpression(n);
+    }
     children[0] = visitExpression(a);
     children[2] = visitExpression(b);
     return node;
   }
 
-  public SimpleNode visitBinaryExpression(SimpleNode node, boolean 
isReferenced, SimpleNode[] children) {
-    SimpleNode op = children[0];
-    SimpleNode a = children[1];
-    SimpleNode b = children[2];
-    children[1] = visitExpression(a);
-    children[2] = visitExpression(b);
-    return node;
-  }
-
   SimpleNode translateAndOrExpression(SimpleNode node, boolean isand, 
SimpleNode a, SimpleNode b) {
     SimpleNode[] children = node.getChildren();
     children[0] = visitExpression(a);
@@ -1700,7 +1711,7 @@
 }
 
 /**
- * @copyright Copyright 2006-2007 Laszlo Systems, Inc.  All Rights
+ * @copyright Copyright 2006-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-01-08 06:00:07 UTC (rev 7762)
+++ 
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java 
    2008-01-08 14:07:37 UTC (rev 7763)
@@ -1,7 +1,7 @@
 /* -*- mode: Java; c-basic-offset: 2; -*- */
 
 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
-* Copyright 2001-2007 Laszlo Systems, Inc.  All Rights Reserved.              *
+* Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
 * Use is subject to license terms.                                            *
 * J_LZ_COPYRIGHT_END *********************************************************/
 
@@ -508,7 +508,7 @@
       {"*", "/", "%"},
       {"+", "-"},
       {"<<", ">>", ">>>"},
-      {"<", "<=", ">", ">=", "instanceof", "in"},
+      {"<", "<=", ">", ">=", "instanceof", "in", "is"},
       {"==", "!=", "===", "!=="},
       {"&"}, {"^"}, {"|"}, {"&&"}, {"||"}, {"?", ":"},
       {"=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", 
"|="},

Modified: openlaszlo/trunk/test/lztest/lztest-class-impl.lzx
===================================================================
--- openlaszlo/trunk/test/lztest/lztest-class-impl.lzx  2008-01-08 06:00:07 UTC 
(rev 7762)
+++ openlaszlo/trunk/test/lztest/lztest-class-impl.lzx  2008-01-08 14:07:37 UTC 
(rev 7763)
@@ -47,7 +47,7 @@
     }
   }
 
-  trait Banana {
+  mixin Banana {
     function Banana () {
       super();
       this.initorder += "/banana";
@@ -84,6 +84,9 @@
     var subInst = new LzSub();
 
     LzTestManager.assertTrue( subInst instanceof LzSub );
+    LzTestManager.assertTrue( subInst is LzSub );
+    LzTestManager.assertFalse( subInst is Number );
+    LzTestManager.assertFalse( subInst is Banana );
     LzTestManager.assertEquals( true, subInst.testAttr );
     LzTestManager.assertEquals( "foo", subInst.testAttr2 );
 
@@ -98,7 +101,11 @@
     var sub2Inst = new LzSubSub();
 
     LzTestManager.assertTrue( sub2Inst instanceof LzSub);
+    LzTestManager.assertTrue( sub2Inst is LzSub);
+    LzTestManager.assertFalse( sub2Inst is Number );
+    LzTestManager.assertFalse( sub2Inst is Banana );
     LzTestManager.assertTrue( sub2Inst instanceof LzSubSub);
+    LzTestManager.assertTrue( sub2Inst is LzSubSub);
 
     LzTestManager.assertEquals( true, sub2Inst.testAttr );
 
@@ -117,6 +124,9 @@
 
     var nodeSubInst = new LzNodeSub();
     LzTestManager.assertTrue( nodeSubInst instanceof LzNodeSub );
+    LzTestManager.assertTrue( nodeSubInst is LzNodeSub );
+    LzTestManager.assertFalse( nodeSubInst is Number );
+    LzTestManager.assertFalse( nodeSubInst is Banana );
 }
 
 suiteSubclasses.testUserClass = function () {
@@ -135,6 +145,9 @@
     
     var insta = new suba(canvas, { name: "insta" }, [], false);
     LzTestManager.assertTrue( insta instanceof suba );
+    LzTestManager.assertTrue( insta is suba );
+    LzTestManager.assertFalse( insta is Number );
+    LzTestManager.assertFalse( insta is Banana );
     
     LzTestManager.assertEquals(0, insta.foocalls);
     insta.foo();
@@ -156,7 +169,11 @@
 
     var instb = new subb(canvas, { name: "instb" }, [], false);
     LzTestManager.assertTrue( instb instanceof subb );
+    LzTestManager.assertTrue( instb is subb );
+    LzTestManager.assertFalse( instb is Number );
+    LzTestManager.assertFalse( instb is Banana );
     LzTestManager.assertTrue( instb instanceof suba );
+    LzTestManager.assertTrue( instb is suba );
     
     LzTestManager.assertEquals(0, instb.foocalls);
     LzTestManager.assertEquals(0, instb.foooverrides);
@@ -165,9 +182,14 @@
     LzTestManager.assertEquals(1, instb.foooverrides);
 }
 
-suiteSubclasses.testTraitSuper = function() {
+suiteSubclasses.testMixinSuper = function() {
   var treat = new Sundae();
     
+  LzTestManager.assertTrue( treat is Sundae, "treat is Sundae" );
+  LzTestManager.assertTrue( treat is Vanilla, "treat is Vanilla" );
+  LzTestManager.assertFalse( treat is Number );
+  // Debug.debug(Testing is on mixins: "%w is %w", treat, Banana)
+  LzTestManager.assertTrue( treat is Banana, "treat is Banana" );
   LzTestManager.assertEquals("/vanilla/banana/sundae", treat.initorder);
   LzTestManager.assertEquals("sundae banana vanilla", treat.test());
 }
@@ -176,7 +198,7 @@
 suiteSubclasses.addTest(suiteSubclasses.testSub); 
 //suiteSubclasses.addTest(suiteSubclasses.testClassNodeSub); 
 //suiteSubclasses.addTest(suiteSubclasses.testUserClass); 
-suiteSubclasses.addTest(suiteSubclasses.testTraitSuper);
+suiteSubclasses.addTest(suiteSubclasses.testMixinSuper);
 
 ]]>
 </script>


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

Reply via email to