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