WSL needs to understand && and ||
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Sep 2017 03:39:19 +0000 (03:39 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Sep 2017 03:39:19 +0000 (03:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177062

Reviewed by Filip Pizlo.

Very similar to LogicalNot.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/Checker.js:
* WebGPUShadingLanguageRI/EBufferBuilder.js:
(EBufferBuilder.prototype.visitLogicalExpression):
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitLogicalExpression):
* WebGPUShadingLanguageRI/Lexer.js:
(Lexer.prototype.next):
(Lexer):
* WebGPUShadingLanguageRI/LogicalExpression.js: Added.
(LogicalExpression):
(LogicalExpression.prototype.get text):
(LogicalExpression.prototype.get left):
(LogicalExpression.prototype.get right):
(LogicalExpression.prototype.toString):
* WebGPUShadingLanguageRI/Parse.js:
(parseLeftLogicalExpression):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitLogicalExpression):
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitProtocolDecl):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222139 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/EBufferBuilder.js
Tools/WebGPUShadingLanguageRI/Evaluator.js
Tools/WebGPUShadingLanguageRI/Lexer.js
Tools/WebGPUShadingLanguageRI/LogicalExpression.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/Visitor.js

index 52cadc4..4478d5b 100644 (file)
@@ -1,5 +1,38 @@
 2017-09-17  Myles C. Maxfield  <mmaxfield@apple.com>
 
+        WSL needs to understand && and ||
+        https://bugs.webkit.org/show_bug.cgi?id=177062
+
+        Reviewed by Filip Pizlo.
+
+        Very similar to LogicalNot.
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/Checker.js:
+        * WebGPUShadingLanguageRI/EBufferBuilder.js:
+        (EBufferBuilder.prototype.visitLogicalExpression):
+        * WebGPUShadingLanguageRI/Evaluator.js:
+        (Evaluator.prototype.visitLogicalExpression):
+        * WebGPUShadingLanguageRI/Lexer.js:
+        (Lexer.prototype.next):
+        (Lexer):
+        * WebGPUShadingLanguageRI/LogicalExpression.js: Added.
+        (LogicalExpression):
+        (LogicalExpression.prototype.get text):
+        (LogicalExpression.prototype.get left):
+        (LogicalExpression.prototype.get right):
+        (LogicalExpression.prototype.toString):
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parseLeftLogicalExpression):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitLogicalExpression):
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        * WebGPUShadingLanguageRI/Visitor.js:
+        (Visitor.prototype.visitProtocolDecl):
+
+2017-09-17  Myles C. Maxfield  <mmaxfield@apple.com>
+
         WSL needs float and double support
         https://bugs.webkit.org/show_bug.cgi?id=177058
 
index 82fadd1..95bf1c8 100644 (file)
@@ -92,6 +92,7 @@ load("LetExpression.js");
 load("Lexer.js");
 load("LexerToken.js");
 load("LiteralTypeChecker.js");
+load("LogicalExpression.js");
 load("LogicalNot.js");
 load("LoopChecker.js");
 load("MakeArrayRefExpression.js");
index 045b7b4..e2171ae 100644 (file)
@@ -257,23 +257,31 @@ class Checker extends Visitor {
         return this._program.intrinsics.bool;
     }
 
+    _requireBool(expression)
+    {
+        let type = expression.visit(this);
+        if (!type)
+            throw new Error("Expression has no type, but should be bool: " + expression);
+        if (!type.equals(this._program.intrinsics.bool))
+            throw new WError("Expression isn't a bool: " + expression);
+    }
+
     visitLogicalNot(node)
     {
-        let resultType = node.operand.visit(this);
-        if (!resultType)
-            throw new Error("Trying to negate something with no type: " + node.operand);
-        if (!resultType.equals(this._program.intrinsics.bool))
-            throw new WError("Trying to negate something that isn't a bool: " + node.operand);
+        this._requireBool(node.operand);
+        return this._program.intrinsics.bool;
+    }
+
+    visitLogicalExpression(node)
+    {
+        this._requireBool(node.left);
+        this._requireBool(node.right);
         return this._program.intrinsics.bool;
     }
 
     visitIfStatement(node)
     {
-        let conditionalResultType = node.conditional.visit(this);
-        if (!conditionalResultType)
-            throw new Error("Trying to negate something with no type: " + node.conditional);
-        if (!conditionalResultType.equals(this._program.intrinsics.bool))
-            throw new WError("Trying to negate something that isn't a bool: " + node.conditional);
+        this._requireBool(node.conditional);
         node.body.visit(this);
         if (node.elseBody)
             node.elseBody.visit(this);
@@ -281,35 +289,22 @@ class Checker extends Visitor {
 
     visitWhileLoop(node)
     {
-        let conditionalResultType = node.conditional.visit(this);
-        if (!conditionalResultType)
-            throw new Error("While loop conditional has no type: " + node.conditional);
-        if (!conditionalResultType.equals(this._program.intrinsics.bool))
-            throw new WError("While loop conditional isn't a bool: " + node.conditional);
+        this._requireBool(node.conditional);
         node.body.visit(this);
     }
 
     visitDoWhileLoop(node)
     {
         node.body.visit(this);
-        let conditionalResultType = node.conditional.visit(this);
-        if (!conditionalResultType)
-            throw new Error("Do-While loop conditional has no type: " + node.conditional);
-        if (!conditionalResultType.equals(this._program.intrinsics.bool))
-            throw new WError("Do-While loop conditional isn't a bool: " + node.conditional);
+        this._requireBool(node.conditional);
     }
 
     visitForLoop(node)
     {
         if (node.initialization)
             node.initialization.visit(this);
-        if (node.condition) {
-            let conditionResultType = node.condition.visit(this);
-            if (!conditionResultType)
-                throw new Error("For loop conditional has no type: " + node.conditional);
-            if (!conditionResultType.equals(this._program.intrinsics.bool))
-                throw new WError("For loop conditional isn't a bool: " + node.conditional);
-        }
+        if (node.condition)
+            this._requireBool(node.condition);
         if (node.increment)
             node.increment.visit(this);
         node.body.visit(this);
index 5e33742..c3bec74 100644 (file)
@@ -104,6 +104,12 @@ class EBufferBuilder extends Visitor {
         super.visitLogicalNot(node);
     }
     
+    visitLogicalExpression(node)
+    {
+        node.ePtr = EPtr.box();
+        super.visitLogicalExpression(node);
+    }
+    
     visitLetExpression(node)
     {
         this._createEPtrForNode(node);
index 5885a6b..1fe65df 100644 (file)
@@ -166,6 +166,24 @@ class Evaluator extends Visitor {
         return node.ePtr.box(result);
     }
 
+    visitLogicalExpression(node)
+    {
+        let lhs = node.left.visit(this).loadValue();
+        let rhs = node.right.visit(this).loadValue();
+        let result;
+        switch (node.text) {
+        case "&&":
+            result = lhs && rhs;
+            break;
+        case "||":
+            result = lhs || rhs;
+            break;
+        default:
+            throw new Error("Unknown type of logical expression");
+        }
+        return node.ePtr.box(result);
+    }
+
     visitIfStatement(node)
     {
         if (node.conditional.visit(this).loadValue())
index e2f3eb2..351d62a 100644 (file)
@@ -123,7 +123,7 @@ class Lexer {
         if (/^[0-9]+/.test(relevantText))
             return result("intLiteral");
         
-        if (/^->|>=|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=|\+\+|--|([{}()\[\]?:=+*\/,.%!~^&|<>@;-])/.test(relevantText))
+        if (/^->|>=|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=|\+\+|--|&&|\|\||([{}()\[\]?:=+*\/,.%!~^&|<>@;-])/.test(relevantText))
             return result("punctuation");
         
         let remaining = relevantText.substring(0, 20).split(/\s/)[0];
diff --git a/Tools/WebGPUShadingLanguageRI/LogicalExpression.js b/Tools/WebGPUShadingLanguageRI/LogicalExpression.js
new file mode 100644 (file)
index 0000000..937dd54
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+class LogicalExpression extends Expression {
+    constructor(origin, text, left, right)
+    {
+        super(origin);
+        this._text = text;
+        this._left = left;
+        this._right = right;
+    }
+    
+    get text() { return this._text; }
+    get left() { return this._left; }
+    get right() { return this._right; }
+    
+    toString()
+    {
+        return "(" + this.left + " " + this.text + " " + this.right + ")";
+    }
+}
+
index 3b81931..dbfa6b3 100644 (file)
@@ -507,7 +507,7 @@ function parse(program, origin, originKind, lineNumberOffset, text)
     {
         return genericParseLeft(
             texts, nextParser,
-            (token, left, right) => new LogicalExpression(token, token.text, left, right));
+            (token, left, right) => new LogicalExpression(token, token.text, new CallExpression(left.origin, "bool", [], [left]), new CallExpression(right.origin, "bool", [], [right])));
     }
     
     function parsePossibleLogicalAnd()
index a81b87f..1f9b575 100644 (file)
@@ -313,6 +313,13 @@ class Rewriter extends VisitorBase {
         result.ePtr = node.ePtr;
         return result;
     }
+    
+    visitLogicalExpression(node)
+    {
+        let result = new LogicalExpression(node.origin, node.text, node.left.visit(this), node.right.visit(this));
+        result.ePtr = node.ePtr;
+        return result;
+    }
 
     visitIfStatement(node)
     {
index 4ed96db..c12fb82 100644 (file)
@@ -69,6 +69,7 @@
 <script src="Lexer.js"></script>
 <script src="LexerToken.js"></script>
 <script src="LiteralTypeChecker.js"></script>
+<script src="LogicalExpression.js"></script>
 <script src="LogicalNot.js"></script>
 <script src="LoopChecker.js"></script>
 <script src="MakeArrayRefExpression.js"></script>
index e11c04b..38bda4b 100644 (file)
@@ -527,8 +527,8 @@ function TEST_badAdd()
 
 function TEST_lexerKeyword()
 {
-    let result = doLex("ident for while 123 123u { } {asd asd{ 1a3 1.2 + 3.4 + 1. + .2 1.2d 0.d .3d");
-    if (result.length != 23)
+    let result = doLex("ident for while 123 123u { } {asd asd{ 1a3 1.2 + 3.4 + 1. + .2 1.2d 0.d .3d && ||");
+    if (result.length != 25)
         throw new Error("Lexer emitted an incorrect number of tokens (expected 23): " + result.length);
     checkLexerToken(result[0],  0,  "identifier",    "ident");
     checkLexerToken(result[1],  6,  "keyword",       "for");
@@ -553,6 +553,8 @@ function TEST_lexerKeyword()
     checkLexerToken(result[20], 63, "floatLiteral",  "1.2d");
     checkLexerToken(result[21], 68, "floatLiteral",  "0.d");
     checkLexerToken(result[22], 72, "floatLiteral",  ".3d");
+    checkLexerToken(result[23], 76, "punctuation",   "&&");
+    checkLexerToken(result[24], 79, "punctuation",   "||");
 }
 
 function TEST_simpleNoReturn()
@@ -2790,6 +2792,52 @@ function TEST_floatMath()
         (e) => e instanceof WTypeError);
 }
 
+function TEST_booleanMath()
+{
+    let program = doPrep(`
+        bool foo()
+        {
+            return true && true;
+        }
+        bool foo2()
+        {
+            return true && false;
+        }
+        bool foo3()
+        {
+            return false && true;
+        }
+        bool foo4()
+        {
+            return false && false;
+        }
+        bool foo5()
+        {
+            return true || true;
+        }
+        bool foo6()
+        {
+            return true || false;
+        }
+        bool foo7()
+        {
+            return false || true;
+        }
+        bool foo8()
+        {
+            return false || false;
+        }
+    `);
+    checkBool(program, callFunction(program, "foo", [], []), true);
+    checkBool(program, callFunction(program, "foo2", [], []), false);
+    checkBool(program, callFunction(program, "foo3", [], []), false);
+    checkBool(program, callFunction(program, "foo4", [], []), false);
+    checkBool(program, callFunction(program, "foo5", [], []), true);
+    checkBool(program, callFunction(program, "foo6", [], []), true);
+    checkBool(program, callFunction(program, "foo7", [], []), true);
+    checkBool(program, callFunction(program, "foo8", [], []), false);
+}
+
 let filter = /.*/; // run everything by default
 if (this["arguments"]) {
     for (let i = 0; i < arguments.length; i++) {
index 7c75332..1ba40e0 100644 (file)
@@ -314,6 +314,12 @@ class Visitor extends VisitorBase {
         node.operand.visit(this);
     }
     
+    visitLogicalExpression(node)
+    {
+        node.left.visit(this);
+        node.right.visit(this);
+    }
+    
     visitFunctionLikeBlock(node)
     {
         if (node.returnType)