[WSL] Ternary expressions appear to be unimplemented
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 21:43:03 +0000 (21:43 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 21:43:03 +0000 (21:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178981

Reviewed by Saam Barati.

Implement ternary statements. These can be both lvalues and rvalues. (a ? b : c ? d : e)
is parsed as (a ? b : (c ? d : e)).

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/Checker.js:
(Checker.prototype.visitTernaryExpression):
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitTernaryExpression):
* WebGPUShadingLanguageRI/NormalUsePropertyResolver.js:
(NormalUsePropertyResolver.prototype.visitTernaryExpression):
(NormalUsePropertyResolver):
* WebGPUShadingLanguageRI/Parse.js:
(parsePossibleTernaryConditional):
* WebGPUShadingLanguageRI/PropertyResolver.js:
(PropertyResolver.prototype._visitRValuesWithinLValue.RValueFinder.prototype.visitTernaryExpression):
(PropertyResolver.prototype._visitRValuesWithinLValue.RValueFinder):
(PropertyResolver.prototype._visitRValuesWithinLValue):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitTernaryExpression):
* WebGPUShadingLanguageRI/SPIRV.html:
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitProtocolDecl):
* WebGPUShadingLanguageRI/index.html:

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

14 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/Evaluator.js
Tools/WebGPUShadingLanguageRI/NormalUsePropertyResolver.js
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/PropertyResolver.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/SPIRV.html
Tools/WebGPUShadingLanguageRI/TernaryExpression.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/Visitor.js
Tools/WebGPUShadingLanguageRI/index.html

index 2939bf5..9846020 100644 (file)
@@ -1,3 +1,36 @@
+2018-08-23  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WSL] Ternary expressions appear to be unimplemented
+        https://bugs.webkit.org/show_bug.cgi?id=178981
+
+        Reviewed by Saam Barati.
+
+        Implement ternary statements. These can be both lvalues and rvalues. (a ? b : c ? d : e)
+        is parsed as (a ? b : (c ? d : e)).
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/Checker.js:
+        (Checker.prototype.visitTernaryExpression):
+        * WebGPUShadingLanguageRI/Evaluator.js:
+        (Evaluator.prototype.visitTernaryExpression):
+        * WebGPUShadingLanguageRI/NormalUsePropertyResolver.js:
+        (NormalUsePropertyResolver.prototype.visitTernaryExpression):
+        (NormalUsePropertyResolver):
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parsePossibleTernaryConditional):
+        * WebGPUShadingLanguageRI/PropertyResolver.js:
+        (PropertyResolver.prototype._visitRValuesWithinLValue.RValueFinder.prototype.visitTernaryExpression):
+        (PropertyResolver.prototype._visitRValuesWithinLValue.RValueFinder):
+        (PropertyResolver.prototype._visitRValuesWithinLValue):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitTernaryExpression):
+        * WebGPUShadingLanguageRI/SPIRV.html:
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        * WebGPUShadingLanguageRI/Visitor.js:
+        (Visitor.prototype.visitProtocolDecl):
+        * WebGPUShadingLanguageRI/index.html:
+
 2018-08-22  Ryosuke Niwa  <rniwa@webkit.org>
 
         Assert in NetworkBlobRegistry::unregisterBlobURL after network process had terminated
index f9a1d99..315bec2 100644 (file)
@@ -153,6 +153,7 @@ load("SynthesizeStructAccessors.js");
 load("SynthesizeOperatorBool.js");
 load("SynthesizeCopyConstructorOperator.js");
 load("SynthesizeDefaultConstructorOperator.js");
+load("TernaryExpression.js");
 load("TrapStatement.js");
 load("TypeDef.js");
 load("TypeDefResolver.js");
index 4fb7ade..c69d554 100644 (file)
@@ -648,6 +648,21 @@ class Checker extends Visitor {
             result = expression.visit(this);
         return result;
     }
+
+    visitTernaryExpression(node)
+    {
+        this._requireBool(node.predicate);
+        let bodyType = node.bodyExpression.visit(this);
+        let elseType = node.elseExpression.visit(this);
+        if (!bodyType)
+            throw new Error("Ternary expression body has no type: " + node.bodyExpression);
+        if (!elseType)
+            throw new Error("Ternary expression else has no type: " + node.elseExpression);
+        if (!bodyType.equalsWithCommit(elseType))
+            throw new WTypeError("Body and else clause of ternary statement don't have the same type: " + node);
+        node.isLValue = node.bodyExpression.isLValue && node.elseExpression.isLValue;
+        return bodyType;
+    }
     
     visitCallExpression(node)
     {
index 394407e..0290de2 100644 (file)
@@ -142,6 +142,14 @@ class Evaluator extends Visitor {
         // This should almost snapshot, except that tail-returning a pointer is totally OK.
         return result;
     }
+
+    visitTernaryExpression(node)
+    {
+        if (node.predicate.visit(this).loadValue())
+            return node.bodyExpression.visit(this);
+        return node.elseExpression.visit(this);
+        
+    }
     
     visitVariableRef(node)
     {
index df45d7e..9af19ee 100644 (file)
@@ -34,5 +34,12 @@ class NormalUsePropertyResolver extends Rewriter {
     {
         return super.visitIndexExpression(node).rewriteAfterCloning();
     }
+
+    visitTernaryExpression(node)
+    {
+        let result = super.visitTernaryExpression(node);
+        result.isLValue = node.isLValue;
+        return result;
+    }
 }
 
index 3be30ee..a20248d 100644 (file)
@@ -520,7 +520,10 @@ function parse(program, origin, originKind, lineNumberOffset, text)
         let operator = tryConsume("?");
         if (!operator)
             return predicate;
-        return new TernaryExpression(operator, predicate, parsePossibleAssignment(), parsePossibleAssignment());
+        let bodyExpression = parsePossibleAssignment();
+        consume(":");
+        let elseExpression = parsePossibleAssignment();
+        return new TernaryExpression(operator, predicate, bodyExpression, elseExpression);
     }
     
     function parsePossibleAssignment(mode)
index 57c600c..b5c454a 100644 (file)
@@ -59,6 +59,10 @@ class PropertyResolver extends Visitor {
             {
                 visit(node.lValue);
             }
+
+            visitTernaryExpression(node)
+            {
+            }
         }
         
         node.visit(new RValueFinder());
index 2901dd5..94d3a76 100644 (file)
@@ -164,6 +164,11 @@ class Rewriter {
         result.addressSpace = node.addressSpace;
         return result;
     }
+
+    visitTernaryExpression(node)
+    {
+        return new TernaryExpression(node.origin, node.predicate.visit(this), node.bodyExpression.visit(this), node.elseExpression.visit(this));
+    }
     
     _handlePropertyAccessExpression(result, node)
     {
index 20be7c8..ff2c02c 100644 (file)
@@ -136,6 +136,7 @@ td {
     <script src="SynthesizeOperatorBool.js"></script>
     <script src="SynthesizeCopyConstructorOperator.js"></script>
     <script src="SynthesizeDefaultConstructorOperator.js"></script>
+    <script src="TernaryExpression.js"></script>
     <script src="TrapStatement.js"></script>
     <script src="TypeDef.js"></script>
     <script src="TypeDefResolver.js"></script>
diff --git a/Tools/WebGPUShadingLanguageRI/TernaryExpression.js b/Tools/WebGPUShadingLanguageRI/TernaryExpression.js
new file mode 100644 (file)
index 0000000..a6f5a00
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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 TernaryExpression extends Expression {
+    constructor(origin, predicate, bodyExpression, elseExpression)
+    {
+        super(origin);
+        this._predicate = predicate;
+        this._bodyExpression = bodyExpression;
+        this._elseExpression = elseExpression;
+        this._isLValue = null; // We use null to indicate that we don't know yet.
+    }
+    
+    get predicate() { return this._predicate; }
+    get bodyExpression() { return this._bodyExpression; }
+    get elseExpression() { return this._elseExpression; }
+    get isLValue() { return this._isLValue; }
+    set isLValue(value) { this._isLValue = value; }
+    
+    toString()
+    {
+        return "(" + this.predicate + ") ? (" + this.bodyExpression + ") : (" + this.elseExpression + ")";
+    }
+}
index 0de6941..7d26d26 100644 (file)
 <script src="SynthesizeOperatorBool.js"></script>
 <script src="SynthesizeCopyConstructorOperator.js"></script>
 <script src="SynthesizeDefaultConstructorOperator.js"></script>
+<script src="TernaryExpression.js"></script>
 <script src="TrapStatement.js"></script>
 <script src="TypeDef.js"></script>
 <script src="TypeDefResolver.js"></script>
index bffbcf0..1d0fa9f 100644 (file)
@@ -198,6 +198,68 @@ tests.commentParsing = function() {
         (e) => e instanceof WSyntaxError);
 }
 
+tests.ternaryExpression = function() {
+    let program = doPrep(`
+        int foo(int x)
+        {
+            return x < 3 ? 4 : 5;
+        }
+        int bar(int x)
+        {
+            int y = 1;
+            int z = 2;
+            (x < 3 ? y : z) = 7;
+            return y;
+        }
+        int baz(int x)
+        {
+            return x < 10 ? 11 : x < 12 ? 14 : 15;
+        }
+        int quux(int x)
+        {
+            return 3 < 4 ? x : 5;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 767)]), 5);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 2)]), 4);
+    checkInt(program, callFunction(program, "bar", [], [makeInt(program, 2)]), 7);
+    checkInt(program, callFunction(program, "bar", [], [makeInt(program, 8)]), 1);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 8)]), 11);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 9)]), 11);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 10)]), 14);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 11)]), 14);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 12)]), 15);
+    checkInt(program, callFunction(program, "baz", [], [makeInt(program, 13)]), 15);
+    checkInt(program, callFunction(program, "quux", [], [makeInt(program, 14)]), 14);
+    checkFail(
+        () => doPrep(`
+            int foo()
+            {
+                int x;
+                (4 < 5 ? x : 7) = 8;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            int foo()
+            {
+                int x;
+                float y;
+                return 4 < 5 ? x : y;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            int foo()
+            {
+                return 4 < 5 ? 6 : 7.0;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+}
+
 tests.literalBool = function() {
     let program = doPrep("bool foo() { return true; }");
     checkBool(program, callFunction(program, "foo", []), true);
index 60dfceb..1f1f54d 100644 (file)
@@ -162,6 +162,13 @@ class Visitor {
     {
         node.ptr.visit(this);
     }
+
+    visitTernaryExpression(node)
+    {
+        node.predicate.visit(this);
+        node.bodyExpression.visit(this);
+        node.elseExpression.visit(this);
+    }
     
     _handlePropertyAccessExpression(node)
     {
index 9c31ce9..2efadbd 100644 (file)
 <script src="SynthesizeOperatorBool.js"></script>
 <script src="SynthesizeCopyConstructorOperator.js"></script>
 <script src="SynthesizeDefaultConstructorOperator.js"></script>
+<script src="TernaryExpression.js"></script>
 <script src="TrapStatement.js"></script>
 <script src="TypeDef.js"></script>
 <script src="TypeDefResolver.js"></script>