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;
+ }
+};
+