Title: [221842] trunk/Tools
Revision
221842
Author
[email protected]
Date
2017-09-10 18:05:05 -0700 (Sun, 10 Sep 2017)

Log Message

WSL should support while loops
https://bugs.webkit.org/show_bug.cgi?id=176581

Reviewed by Filip Pizlo.

There are a few interesting pieces to this patch:
1. Because the evaluator is just a node-based descent through the tree, the implementation of break
and continue are just "throw".
2. The ReturnChecker now has to return a three-state enum because of nested blocks. The outer block
cares about if the inner block has "break" as opposed to it having no returns nor breaks/continues.
3. ReturnChecker will treat "while (true)" the same as { }, but will not descend deeper for things
like "while (3 == 3)".
4. This patch also adds a few more boolean conditional functions like operator<().
5. I added another pass which makes sure there are no bare break/return keywords outside of loops.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/Break.js: Copied from Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js.
(Break):
(Break.prototype.get origin):
(Break.prototype.toString):
* WebGPUShadingLanguageRI/CheckLoops.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
(checkLoops):
* WebGPUShadingLanguageRI/CheckReturns.js:
(checkReturns):
* WebGPUShadingLanguageRI/CheckUnreachableCode.js:
(checkUnreachableCode):
* WebGPUShadingLanguageRI/Checker.js:
* WebGPUShadingLanguageRI/Continue.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
(Continue):
(Continue.prototype.get origin):
(Continue.prototype.toString):
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitWhileLoop):
(Evaluator.prototype.visitBreak):
(Evaluator.prototype.visitContinue):
* WebGPUShadingLanguageRI/Intrinsics.js:
(Intrinsics):
* WebGPUShadingLanguageRI/Lexer.js:
(Lexer.prototype.next):
(Lexer):
* WebGPUShadingLanguageRI/LoopChecker.js: Copied from Tools/WebGPUShadingLanguageRI/ReturnChecker.js.
(LoopChecker):
(LoopChecker.prototype.visitFuncDef):
(LoopChecker.prototype.visitWhileLoop):
(LoopChecker.prototype.visitBreak):
(LoopChecker.prototype.visitContinue):
* WebGPUShadingLanguageRI/NameResolver.js:
(NameResolver.prototype.visitWhileLoop):
* WebGPUShadingLanguageRI/Node.js:
(Node.prototype.visit):
* WebGPUShadingLanguageRI/Parse.js:
(parsePossibleRelationalInequality):
(parseBreak):
(parseContinue):
(parseWhile):
* WebGPUShadingLanguageRI/Prepare.js:
(prepare):
* WebGPUShadingLanguageRI/ReturnChecker.js:
(ReturnChecker):
(ReturnChecker.prototype.visitFuncDef):
(ReturnChecker.prototype.visitBlock):
(ReturnChecker.prototype.visitIfStatement):
(ReturnChecker.prototype.visitWhileLoop):
(ReturnChecker.prototype.visitReturn):
(ReturnChecker.prototype.visitBreak):
(ReturnChecker.prototype.visitContinue):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitContinue):
(Rewriter.prototype.visitBreak):
(Rewriter.prototype.visitWhileLoop):
(Rewriter):
* WebGPUShadingLanguageRI/StandardLibraryPrologue.js:
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
(TEST_returnIf):
(TEST_simpleWhile):
* WebGPUShadingLanguageRI/UnreachableCodeChecker.js:
(UnreachableCodeChecker):
(UnreachableCodeChecker.prototype.visitBlock):
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitWhileLoop):
(Visitor.prototype.visitContinue):
(Visitor.prototype.visitBreak):
* WebGPUShadingLanguageRI/WhileLoop.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
(WhileLoop):
(WhileLoop.prototype.get origin):
(WhileLoop.prototype.get conditional):
(WhileLoop.prototype.get body):
(WhileLoop.prototype.toString):

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (221841 => 221842)


--- trunk/Tools/ChangeLog	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/ChangeLog	2017-09-11 01:05:05 UTC (rev 221842)
@@ -1,3 +1,95 @@
+2017-09-10  Myles C. Maxfield  <[email protected]>
+
+        WSL should support while loops
+        https://bugs.webkit.org/show_bug.cgi?id=176581
+
+        Reviewed by Filip Pizlo.
+
+        There are a few interesting pieces to this patch:
+        1. Because the evaluator is just a node-based descent through the tree, the implementation of break
+        and continue are just "throw".
+        2. The ReturnChecker now has to return a three-state enum because of nested blocks. The outer block
+        cares about if the inner block has "break" as opposed to it having no returns nor breaks/continues.
+        3. ReturnChecker will treat "while (true)" the same as { }, but will not descend deeper for things
+        like "while (3 == 3)".
+        4. This patch also adds a few more boolean conditional functions like operator<().
+        5. I added another pass which makes sure there are no bare break/return keywords outside of loops.
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/Break.js: Copied from Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js.
+        (Break):
+        (Break.prototype.get origin):
+        (Break.prototype.toString):
+        * WebGPUShadingLanguageRI/CheckLoops.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
+        (checkLoops):
+        * WebGPUShadingLanguageRI/CheckReturns.js:
+        (checkReturns):
+        * WebGPUShadingLanguageRI/CheckUnreachableCode.js:
+        (checkUnreachableCode):
+        * WebGPUShadingLanguageRI/Checker.js:
+        * WebGPUShadingLanguageRI/Continue.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
+        (Continue):
+        (Continue.prototype.get origin):
+        (Continue.prototype.toString):
+        * WebGPUShadingLanguageRI/Evaluator.js:
+        (Evaluator.prototype.visitWhileLoop):
+        (Evaluator.prototype.visitBreak):
+        (Evaluator.prototype.visitContinue):
+        * WebGPUShadingLanguageRI/Intrinsics.js:
+        (Intrinsics):
+        * WebGPUShadingLanguageRI/Lexer.js:
+        (Lexer.prototype.next):
+        (Lexer):
+        * WebGPUShadingLanguageRI/LoopChecker.js: Copied from Tools/WebGPUShadingLanguageRI/ReturnChecker.js.
+        (LoopChecker):
+        (LoopChecker.prototype.visitFuncDef):
+        (LoopChecker.prototype.visitWhileLoop):
+        (LoopChecker.prototype.visitBreak):
+        (LoopChecker.prototype.visitContinue):
+        * WebGPUShadingLanguageRI/NameResolver.js:
+        (NameResolver.prototype.visitWhileLoop):
+        * WebGPUShadingLanguageRI/Node.js:
+        (Node.prototype.visit):
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parsePossibleRelationalInequality):
+        (parseBreak):
+        (parseContinue):
+        (parseWhile):
+        * WebGPUShadingLanguageRI/Prepare.js:
+        (prepare):
+        * WebGPUShadingLanguageRI/ReturnChecker.js:
+        (ReturnChecker):
+        (ReturnChecker.prototype.visitFuncDef):
+        (ReturnChecker.prototype.visitBlock):
+        (ReturnChecker.prototype.visitIfStatement):
+        (ReturnChecker.prototype.visitWhileLoop):
+        (ReturnChecker.prototype.visitReturn):
+        (ReturnChecker.prototype.visitBreak):
+        (ReturnChecker.prototype.visitContinue):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitContinue):
+        (Rewriter.prototype.visitBreak):
+        (Rewriter.prototype.visitWhileLoop):
+        (Rewriter):
+        * WebGPUShadingLanguageRI/StandardLibraryPrologue.js:
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        (TEST_returnIf):
+        (TEST_simpleWhile):
+        * WebGPUShadingLanguageRI/UnreachableCodeChecker.js:
+        (UnreachableCodeChecker):
+        (UnreachableCodeChecker.prototype.visitBlock):
+        * WebGPUShadingLanguageRI/Visitor.js:
+        (Visitor.prototype.visitWhileLoop):
+        (Visitor.prototype.visitContinue):
+        (Visitor.prototype.visitBreak):
+        * WebGPUShadingLanguageRI/WhileLoop.js: Copied from Tools/WebGPUShadingLanguageRI/CheckReturns.js.
+        (WhileLoop):
+        (WhileLoop.prototype.get origin):
+        (WhileLoop.prototype.get conditional):
+        (WhileLoop.prototype.get body):
+        (WhileLoop.prototype.toString):
+
 2017-09-07  Filip Pizlo  <[email protected]>
 
         WSL overload resolution should not be cascading

Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/All.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -39,11 +39,13 @@
 load("Assignment.js");
 load("Block.js");
 load("BoolLiteral.js");
+load("Break.js");
 load("CallAssignment.js");
 load("CallExpression.js");
 load("CallFunction.js");
 load("Check.js");
 load("CheckLiteralTypes.js");
+load("CheckLoops.js");
 load("CheckRecursion.js");
 load("CheckReturns.js");
 load("CheckUnreachableCode.js");
@@ -50,7 +52,9 @@
 load("Checker.js");
 load("CommaExpression.js");
 load("ConstexprTypeParameter.js");
+load("Continue.js");
 load("DereferenceExpression.js");
+load("DoWhileLoop.js");
 load("DotExpression.js");
 load("EArrayRef.js");
 load("EBuffer.js");
@@ -76,6 +80,7 @@
 load("LexerToken.js");
 load("LiteralTypeChecker.js");
 load("LogicalNot.js");
+load("LoopChecker.js");
 load("MakePtrExpression.js");
 load("NameContext.js");
 load("NameResolver.js");
@@ -121,3 +126,4 @@
 load("WSyntaxError.js");
 load("WTrapError.js");
 load("WTypeError.js");
+load("WhileLoop.js");

Copied: trunk/Tools/WebGPUShadingLanguageRI/Break.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Break.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/Break.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -0,0 +1,41 @@
+/*
+ * 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 Break extends Node {
+    constructor(origin)
+    {
+        super();
+        this._origin = origin;
+    }
+    
+    get origin() { return this._origin; }
+    
+    toString()
+    {
+        return "break";
+    }
+};
+

Copied: trunk/Tools/WebGPUShadingLanguageRI/CheckLoops.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/CheckLoops.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/CheckLoops.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -0,0 +1,31 @@
+/*
+ * 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";
+
+function checkLoops(program)
+{
+    program.visit(new LoopChecker());
+}
+

Modified: trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -26,6 +26,6 @@
 
 function checkReturns(program)
 {
-    program.visit(new ReturnChecker());
+    program.visit(new ReturnChecker(program));
 }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -26,6 +26,6 @@
 
 function checkUnreachableCode(program)
 {
-    program.visit(new UnreachableCodeChecker());
+    program.visit(new UnreachableCodeChecker(program));
 }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -237,6 +237,26 @@
         if (node.elseBody)
             node.elseBody.visit(this);
     }
+
+    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);
+        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);
+    }
     
     visitCommaExpression(node)
     {

Copied: trunk/Tools/WebGPUShadingLanguageRI/Continue.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Continue.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/Continue.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -0,0 +1,41 @@
+/*
+ * 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 Continue extends Node {
+    constructor(origin)
+    {
+        super();
+        this._origin = origin;
+    }
+    
+    get origin() { return this._origin; }
+    
+    toString()
+    {
+        return "Continue";
+    }
+};
+

Copied: trunk/Tools/WebGPUShadingLanguageRI/DoWhileLoop.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/CheckReturns.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/DoWhileLoop.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/DoWhileLoop.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -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 DoWhileLoop extends Node {
+    constructor(origin, body, conditional)
+    {
+        super();
+        this._origin = origin;
+        this._body = body;
+        this._conditional = conditional;
+    }
+
+    get origin() { return this._origin; }
+    get body() { return this._body; }
+    get conditional() { return this._conditional; }
+
+    toString()
+    {
+        return "do " + this.body + " while (" + this.conditional + ");";
+    }
+};
+

Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -159,6 +159,46 @@
         else if (node.elseBody)
             return node.elseBody.visit(this);
     }
+
+    visitWhileLoop(node)
+    {
+        while (node.conditional.visit(this).loadValue()) {
+            try {
+                node.body.visit(this);
+            } catch (e) {
+                if (e instanceof Break)
+                    break;
+                if (e instanceof Continue)
+                    continue;
+                throw e;
+            }
+        }
+    }
+
+    visitDoWhileLoop(node)
+    {
+        do {
+            try {
+                node.body.visit(this);
+            } catch (e) {
+                if (e instanceof Break)
+                    break;
+                if (e instanceof Continue)
+                    continue;
+                throw e;
+            }
+        } while (node.conditional.visit(this).loadValue());
+    }
+
+    visitBreak(node)
+    {
+        throw node;
+    }
+
+    visitContinue(node)
+    {
+        throw node;
+    }
     
     visitCallExpression(node)
     {

Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -178,6 +178,62 @@
                     EPtr.box(left.loadValue() == right.loadValue());
             });
         
+        this._map.set(
+            "native bool operator<<>(int,int)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() < right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator<<>(uint,uint)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() < right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator<=<>(int,int)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() <= right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator<=<>(uint,uint)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() <= right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator><>(int,int)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() > right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator><>(uint,uint)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() > right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator>=<>(int,int)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() >= right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator>=<>(uint,uint)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() >= right.loadValue());
+            });
+        
         let arrayElementPtr = func => {
             func.implementation = ([ref, index], node) => {
                 ref = ref.loadValue();

Modified: trunk/Tools/WebGPUShadingLanguageRI/Lexer.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Lexer.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Lexer.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -123,7 +123,7 @@
         if (/^([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)/.test(relevantText))
             return result("doubleLiteral");
         
-        if (/^->|=>|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=|([{}()\[\]?:=+*\/,.%!~^&|<>@;-])/.test(relevantText))
+        if (/^->|>=|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=|([{}()\[\]?:=+*\/,.%!~^&|<>@;-])/.test(relevantText))
             return result("punctuation");
         
         let remaining = relevantText.substring(0, 20).split(/\s/)[0];

Copied: trunk/Tools/WebGPUShadingLanguageRI/LoopChecker.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/ReturnChecker.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/LoopChecker.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/LoopChecker.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -0,0 +1,79 @@
+/*
+ * 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 LoopChecker extends Visitor {
+    constructor()
+    {
+        super();
+        this._loopDepth = 0;
+    }
+
+    visitFuncDef(node)
+    {
+        if (this._loopDepth != 0) {
+            throw new Error("LoopChecker does not understand nested functions.");
+        }
+        super.visitFuncDef(node);
+    }
+
+    visitWhileLoop(node)
+    {
+        node.conditional.visit(this);
+        ++this._loopDepth;
+        node.body.visit(this);
+        if (this._loopDepth == 0) {
+            throw new Error("The number of nested loops is negative!");
+        }
+        --this._loopDepth;
+    }
+
+    visitDoWhileLoop(node)
+    {
+        ++this._loopDepth;
+        node.body.visit(this);
+        if (this._loopDepth == 0) {
+            throw new Error("The number of nested loops is negative!");
+        }
+        --this._loopDepth;
+        node.conditional.visit(this);
+    }
+    
+    visitBreak(node)
+    {
+        if (this._loopDepth == 0) {
+            throw new WError("Break statement without enclosing loop!");
+        }
+        super.visitBreak(node);
+    }
+    
+    visitContinue(node)
+    {
+        if (this._loopDepth == 0) {
+            throw new WError("Continue statement without enclosing loop!");
+        }
+        super.visitContinue(node);
+    }
+}

Modified: trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -95,11 +95,25 @@
     visitIfStatement(node)
     {
         node.conditional.visit(this);
-        // If statement's bodies might not be Blocks, so we need to explicitly give them a new context.
+        // The bodies might not be Blocks, so we need to explicitly give them a new context.
         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
         if (node.elseBody)
             node.elseBody.visit(new NameResolver(new NameContext(this._nameContext)));
     }
+
+    visitWhileLoop(node)
+    {
+        node.conditional.visit(this);
+        // The bodies might not be Blocks, so we need to explicitly give them a new context.
+        node.body.visit(new NameResolver(new NameContext(this._nameContext)));
+    }
+
+    visitDoWhileLoop(node)
+    {
+        // The bodies might not be Blocks, so we need to explicitly give them a new context.
+        node.body.visit(new NameResolver(new NameContext(this._nameContext)));
+        node.conditional.visit(this);
+    }
     
     visitProtocolDecl(node)
     {

Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -404,7 +404,7 @@
     
     function parsePossibleRelationalInequality()
     {
-        return parseLeftOperatorCall(["<", ">", "<=", "=>"], parsePossibleShift);
+        return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift);
     }
     
     function parsePossibleRelationalEquality()
@@ -535,6 +535,20 @@
         consume(";");
         return new Return(origin, _expression_);
     }
+    
+    function parseBreak()
+    {
+        let origin = consume("break");
+        consume(";");
+        return new Break(origin);
+    }
+    
+    function parseContinue()
+    {
+        let origin = consume("continue");
+        consume(";");
+        return new Continue(origin);
+    }
 
     function parseIfStatement()
     {
@@ -548,6 +562,27 @@
             elseBody = parseStatement();
         return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [], [conditional]), body, elseBody);
     }
+
+    function parseWhile()
+    {
+        let origin = consume("while");
+        consume("(");
+        let conditional = parseExpression();
+        consume(")");
+        let body = parseStatement();
+        return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [], [conditional]), body);
+    }
+
+    function parseDo()
+    {
+        let origin = consume("do");
+        let body = parseStatement();
+        consume("while");
+        consume("(");
+        let conditional = parseExpression();
+        consume(")");
+        return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [], [conditional]));
+    }
     
     function parseVariableDecls()
     {

Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -35,6 +35,7 @@
     checkLiteralTypes(program);
     checkReturns(program);
     checkUnreachableCode(program);
+    checkLoops(program);
     checkRecursion(program);
     inline(program);
     return program;

Modified: trunk/Tools/WebGPUShadingLanguageRI/ReturnChecker.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/ReturnChecker.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/ReturnChecker.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -25,31 +25,96 @@
 "use strict";
 
 class ReturnChecker extends Visitor {
+    constructor(program)
+    {
+        super();
+        this.returnStyle = {
+            DefinitelyReturns: "Definitely Returns",
+            DefinitelyDoesntReturn: "Definitely Doesn't Return",
+            HasntReturnedYet: "Hasn't Returned Yet"
+        };
+        this._program = program;
+    }
+
     visitFuncDef(node)
     {
         if (node.returnType.equals(node.program.intrinsics.void))
             return;
         
-        if (!node.body.visit(this))
+        let bodyValue = node.body.visit(this);
+        if (bodyValue == this.returnStyle.DefinitelyDoesntReturn || bodyValue == this.returnStyle.HasntReturnedYet)
             throw new WTypeError(node.origin.originString, "Function does not return");
     }
     
     visitBlock(node)
     {
-        // FIXME: This isn't right for break/continue.
-        // https://bugs.webkit.org/show_bug.cgi?id=176263
-        return node.statements.reduce((result, statement) => result || statement.visit(this), false);
+        for (let statement of node.statements) {
+            switch (statement.visit(this)) {
+            case this.returnStyle.DefinitelyReturns:
+                return this.returnStyle.DefinitelyReturns;
+            case this.returnStyle.DefinitelyDoesntReturn:
+                return this.returnStyle.DefinitelyDoesntReturn;
+            case this.returnStyle.HasntReturnedYet:
+                continue;
+            }
+        }
+        return this.returnStyle.HasntReturnedYet;
     }
 
     visitIfStatement(node)
     {
-        return node.elseBody && node.body.visit(this) && node.elseBody.visit(this);
+        if (node.elseBody) {
+            let bodyValue = node.body.visit(this);
+            let elseValue = node.elseBody.visit(this);
+            if (bodyValue == this.returnStyle.DefinitelyReturns && elseValue == this.returnStyle.DefinitelyReturns)
+                return this.returnStyle.DefinitelyReturns;
+            if (bodyValue == this.returnStyle.DefinitelyDoesntReturn && elseValue == this.returnStyle.DefinitelyDoesntReturn)
+                return this.returnStyle.DefinitelyDoesntReturn;
+        }
+        return this.returnStyle.HasntReturnedYet;
     }
 
-    // If a loop returns, then it counts only if the loop is guaranteed to run at least once.
+    visitWhileLoop(node)
+    {
+        if (node.conditional instanceof CallExpression && node.conditional.isCast && node.conditional.returnType instanceof TypeRef && node.conditional.returnType.equals(this._program.intrinsics.bool) && node.conditional.argumentList.length == 1 && node.conditional.argumentList[0].list.length == 1 && node.conditional.argumentList[0].list[0] instanceof BoolLiteral && node.conditional.argumentList[0].list[0].value) {
+            switch (node.body.visit(this)) {
+            case this.returnStyle.DefinitelyReturns:
+                return this.returnStyle.DefinitelyReturns;
+            case this.returnStyle.DefinitelyDoesntReturn:
+            case this.returnStyle.HasntReturnedYet:
+                return this.returnStyle.HasntReturnedYet;
+            }
+        } else
+            node.conditional.visit(this);
+        return this.returnStyle.HasntReturnedYet;
+    }
+
+    visitDoWhileLoop(node)
+    {
+        let result;
+        switch (node.body.visit(this)) {
+        case this.returnStyle.DefinitelyReturns:
+            result = this.returnStyle.DefinitelyReturns;
+        case this.returnStyle.DefinitelyDoesntReturn:
+        case this.returnStyle.HasntReturnedYet:
+            result = this.returnStyle.HasntReturnedYet;
+        }
+        node.conditional.visit(this);
+        return result;
+    }
     
     visitReturn(node)
     {
-        return true;
+        return this.returnStyle.DefinitelyReturns;
     }
+
+    visitBreak(node)
+    {
+        return this.returnStyle.DefinitelyDoesntReturn;
+    }
+
+    visitContinue(node)
+    {
+        return this.returnStyle.DefinitelyDoesntReturn;
+    }
 }

Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -200,6 +200,16 @@
         return new Return(node.origin, node.value ? node.value.visit(this) : null);
     }
     
+    visitContinue(node)
+    {
+        return new Continue(node.origin);
+    }
+    
+    visitBreak(node)
+    {
+        return new Break(node.origin);
+    }
+    
     visitIntLiteral(node)
     {
         let result = new IntLiteral(node.origin, node.value);
@@ -283,5 +293,15 @@
     {
         return new IfStatement(node.origin, node.conditional.visit(this), node.body.visit(this), node.elseBody ? node.elseBody.visit(this) : undefined);
     }
+
+    visitWhileLoop(node)
+    {
+        return new WhileLoop(node.origin, node.conditional.visit(this), node.body.visit(this));
+    }
+
+    visitDoWhileLoop(node)
+    {
+        return new DoWhileLoop(node.origin, node.body.visit(this), node.conditional.visit(this));
+    }
 }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -52,6 +52,14 @@
 native bool operator==(int, int);
 native bool operator==(uint, uint);
 native bool operator==(bool, bool);
+native bool operator<(int, int);
+native bool operator<(uint, uint);
+native bool operator<=(int, int);
+native bool operator<=(uint, uint);
+native bool operator>(int, int);
+native bool operator>(uint, uint);
+native bool operator>=(int, int);
+native bool operator>=(uint, uint);
 
 protocol Equatable {
     bool operator==(Equatable, Equatable);

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.html	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html	2017-09-11 01:05:05 UTC (rev 221842)
@@ -15,11 +15,13 @@
 <script src=""
 <script src=""
 <script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""
 <script src=""
 <script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""
@@ -26,6 +28,8 @@
 <script src=""
 <script src=""
 <script src=""
+<script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""
@@ -52,6 +56,7 @@
 <script src=""
 <script src=""
 <script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""
@@ -97,6 +102,7 @@
 <script src=""
 <script src=""
 <script src=""
+<script src=""
 
 <script src=""
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -1334,8 +1334,31 @@
             }
         `),
         (e) => e instanceof WTypeError);
+    program = doPrep(`
+        int foo(int x)
+        {
+            int y = 6;
+            if (x == 7)
+                int y = 8;
+            return y;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 6);
 }
 
+function TEST_simpleWhile()
+{
+    let program = doPrep(`
+        int foo(int x)
+        {
+            while (x < 13)
+                x = x * 2;
+            return x;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 16);
+}
+
 function TEST_protocolMonoPolySigDoublePolyDefExplicit()
 {
     checkFail(
@@ -1400,6 +1423,180 @@
     `);
 }
 
+function TEST_break()
+{
+    let program = doPrep(`
+        int foo(int x)
+        {
+            while (true) {
+                x = x * 2;
+                if (x >= 7)
+                    break;
+            }
+            return x;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 20);
+    program = doPrep(`
+        int foo(int x)
+        {
+            while (true) {
+                while (true) {
+                    x = x * 2;
+                    if (x >= 7)
+                        break;
+                }
+                x = x - 1;
+                break;
+            }
+            return x;
+            
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 10)]), 19);
+    checkFail(
+        () => doPrep(`
+            int foo(int x)
+            {
+                while (true) {
+                    {
+                        break;
+                    }
+                    x = x + 1;
+                }
+                return x;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            int foo(int x)
+            {
+                break;
+                return x;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    program = doPrep(`
+            int foo(int x)
+            {
+                while (true) {
+                    if (x == 7) {
+                        break;
+                    }
+                    x = x + 1;
+                }
+                return x;
+            }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 7);
+    program = doPrep(`
+            int foo(int x)
+            {
+                while (true) {
+                    break;
+                }
+                return x;
+            }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 1);
+    program = doPrep(`
+            int foo()
+            {
+                while (true) {
+                    return 7;
+                }
+            }
+    `);
+    checkInt(program, callFunction(program, "foo", [], []), 7);
+    checkFail(
+        () => doPrep(`
+            int foo(int x)
+            {
+                while(true) {
+                    break;
+                    return 7;
+                }
+            }
+        `),
+        (e) => e instanceof WTypeError);
+}
+
+function TEST_continue()
+{
+    let program = doPrep(`
+        int foo(int x)
+        {
+            while (x < 10) {
+                if (x == 8) {
+                    x = x + 1;
+                    continue;
+                }
+                x = x * 2;
+            }
+            return x;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 18);
+    checkFail(
+        () => doPrep(`
+            int foo(int x)
+            {
+                continue;
+                return x;
+                
+            }
+        `),
+        (e) => e instanceof WTypeError);
+}
+
+function TEST_doWhile()
+{
+    let program = doPrep(`
+        int foo(int x)
+        {
+            int y = 7;
+            do {
+                y = 8;
+                break;
+            } while (x < 10);
+            return y;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 11)]), 8);
+    program = doPrep(`
+        int foo(int x)
+        {
+            int y = 7;
+            do {
+                y = 8;
+                break;
+            } while (y == 7);
+            return y;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 1)]), 8);
+    program = doPrep(`
+        int foo(int x)
+        {
+            int sum = 0;
+            do {
+                if (x == 11) {
+                    x = 15;
+                    continue;
+                }
+                sum = sum + x;
+                x = x + 1;
+            } while (x < 13);
+            return sum;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", [], [makeInt(program, 9)]), 19);
+}
+
 let filter = /.*/; // run everything by default
 if (this["arguments"]) {
     for (let i = 0; i < arguments.length; i++) {

Modified: trunk/Tools/WebGPUShadingLanguageRI/UnreachableCodeChecker.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/UnreachableCodeChecker.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/UnreachableCodeChecker.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -25,22 +25,25 @@
 "use strict";
 
 class UnreachableCodeChecker extends Visitor {
-    constructor()
+    constructor(program)
     {
         super();
-        this._returnChecker = new ReturnChecker();
+        this._returnChecker = new ReturnChecker(program);
     }
     
     visitBlock(node)
     {
+        super.visitBlock(node);
         for (let i = 0; i < node.statements.length - 1; ++i) {
-            let statement = node.statements[i];
-            // FIXME: Need to also check if this statement can break or continue.
-            // https://bugs.webkit.org/show_bug.cgi?id=176263
-            if (statement.visit(this._returnChecker))
+            switch(node.statements[i].visit(this._returnChecker)) {
+            case this._returnChecker.returnStyle.DefinitelyReturns:
+            case this._returnChecker.returnStyle.DefinitelyDoesntReturn:
                 throw new WTypeError(
                     node.statements[i + 1].origin.originString,
                     "Unreachable code");
+            case this._returnChecker.returnStyle.HasntReturnedYet:
+                continue;
+            }
         }
     }
 }

Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (221841 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js	2017-09-11 00:59:19 UTC (rev 221841)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -215,6 +215,18 @@
         if (node.elseBody)
             node.elseBody.visit(this);
     }
+    
+    visitWhileLoop(node)
+    {
+        node.conditional.visit(this);
+        node.body.visit(this);
+    }
+    
+    visitDoWhileLoop(node)
+    {
+        node.body.visit(this);
+        node.conditional.visit(this);
+    }
 
     visitReturn(node)
     {
@@ -221,6 +233,14 @@
         if (node.value)
             node.value.visit(this);
     }
+
+    visitContinue(node)
+    {
+    }
+
+    visitBreak(node)
+    {
+    }
     
     visitIntLiteral(node)
     {

Copied: trunk/Tools/WebGPUShadingLanguageRI/WhileLoop.js (from rev 221840, trunk/Tools/WebGPUShadingLanguageRI/CheckUnreachableCode.js) (0 => 221842)


--- trunk/Tools/WebGPUShadingLanguageRI/WhileLoop.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/WhileLoop.js	2017-09-11 01:05:05 UTC (rev 221842)
@@ -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 WhileLoop extends Node {
+    constructor(origin, conditional, body)
+    {
+        super();
+        this._origin = origin;
+        this._conditional = conditional;
+        this._body = body;
+    }
+
+    get origin() { return this._origin; }
+    get conditional() { return this._conditional; }
+    get body() { return this._body; }
+
+    toString()
+    {
+        return "while (" + this.conditional + ") " + this.body;
+    }
+};
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to