Diff
Modified: trunk/Tools/ChangeLog (222199 => 222200)
--- trunk/Tools/ChangeLog 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/ChangeLog 2017-09-19 03:44:25 UTC (rev 222200)
@@ -1,5 +1,112 @@
2017-09-18 Filip Pizlo <[email protected]>
+ WSL should support enum
+ https://bugs.webkit.org/show_bug.cgi?id=176977
+
+ Reviewed by Myles Maxfield.
+
+ This implements enum. Enums members are referenced Java-style. For example, if we have an enum like:
+
+ enum Bank {
+ GP,
+ FP
+ }
+
+ Then you refer to the members by saying Bank.GP and Bank.FP.
+
+ Also adds a hack that makes operator- on a literal fold the literal. This fixes two issues:
+
+ - Lets you use negative literals in constexprs.
+ - Means that negative literals also get literal type unification.
+
+ WSL's constexpr support is really thin, but I think it's all we really need for now.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/Checker.js:
+ (Checker.prototype.visitEnumType):
+ (Checker.prototype.visitEnumLiteral):
+ * WebGPUShadingLanguageRI/ConstexprFolder.js: Added.
+ (ConstexprFolder.prototype.visitCallExpression):
+ (ConstexprFolder.prototype.visitTypeOrVariableRef):
+ (ConstexprFolder):
+ * WebGPUShadingLanguageRI/CreateLiteral.js:
+ (createLiteral.GenericLiteral.prototype.get valueForSelectedType):
+ (createLiteral.GenericLiteral.prototype.get negConstexpr):
+ * WebGPUShadingLanguageRI/DoubleLiteral.js:
+ (let.DoubleLiteral.createLiteral.negConstexpr):
+ * WebGPUShadingLanguageRI/EBufferBuilder.js:
+ (EBufferBuilder.prototype.visitEnumLiteral):
+ * WebGPUShadingLanguageRI/EnumLiteral.js: Added.
+ (EnumLiteral):
+ (EnumLiteral.prototype.get member):
+ (EnumLiteral.prototype.get type):
+ (EnumLiteral.prototype.get isConstexpr):
+ (EnumLiteral.prototype.unifyImpl):
+ (EnumLiteral.prototype.toString):
+ * WebGPUShadingLanguageRI/EnumMember.js: Added.
+ (EnumMember):
+ (EnumMember.prototype.get origin):
+ (EnumMember.prototype.get name):
+ (EnumMember.prototype.toString):
+ * WebGPUShadingLanguageRI/EnumType.js: Added.
+ (EnumType):
+ (EnumType.prototype.add):
+ (EnumType.prototype.get origin):
+ (EnumType.prototype.get name):
+ (EnumType.prototype.get baseType):
+ (EnumType.prototype.get memberNames):
+ (EnumType.prototype.memberByName):
+ (EnumType.prototype.get members):
+ (EnumType.prototype.get memberMap):
+ (EnumType.prototype.get isPrimitive):
+ (EnumType.prototype.populateDefaultValue):
+ (EnumType.prototype.get size):
+ (EnumType.prototype.toString):
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype.visitGenericLiteral):
+ (Evaluator.prototype.visitEnumLiteral):
+ * WebGPUShadingLanguageRI/FloatLiteral.js:
+ (let.FloatLiteral.createLiteral.negConstexpr):
+ * WebGPUShadingLanguageRI/FoldConstexprs.js: Added.
+ (foldConstexprs):
+ * WebGPUShadingLanguageRI/IntLiteral.js:
+ (let.IntLiteral.createLiteral.negConstexpr):
+ * WebGPUShadingLanguageRI/Intrinsics.js:
+ (Intrinsics):
+ * WebGPUShadingLanguageRI/NameResolver.js:
+ (NameResolver.prototype.visitProtocolDecl):
+ * WebGPUShadingLanguageRI/Parse.js:
+ (parseConstexpr):
+ (parsePossibleSuffix):
+ (parseEnumMember):
+ (parseEnumType):
+ (parse):
+ * WebGPUShadingLanguageRI/Prepare.js:
+ (prepare):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitEnumType):
+ (Rewriter.prototype.visitEnumMember):
+ (Rewriter.prototype.visitEnumLiteral):
+ * WebGPUShadingLanguageRI/StructType.js:
+ (StructType.prototype.get origin):
+ (StructType.prototype.instantiate):
+ * WebGPUShadingLanguageRI/SynthesizeEnumFunctions.js: Added.
+ (synthesizeEnumFunctions):
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (checkEnum):
+ (TEST_simpleEnum):
+ (TEST_enumWithManualValues):
+ (TEST_enumWithoutZero):
+ (TEST_enumConstexprGenericFunction):
+ (TEST_enumConstexprGenericStruct):
+ * WebGPUShadingLanguageRI/UintLiteral.js:
+ (let.UintLiteral.createLiteral.negConstexpr):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitProtocolDecl):
+
+2017-09-18 Filip Pizlo <[email protected]>
+
WSL prepare() should cache the parsed standard library
https://bugs.webkit.org/show_bug.cgi?id=177118
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -56,6 +56,7 @@
load("Checker.js");
load("CloneProgram.js");
load("CommaExpression.js");
+load("ConstexprFolder.js");
load("ConstexprTypeParameter.js");
load("Continue.js");
load("ConvertPtrToArrayRefExpression.js");
@@ -68,6 +69,9 @@
load("EBuffer.js");
load("EBufferBuilder.js");
load("EPtr.js");
+load("EnumLiteral.js");
+load("EnumMember.js");
+load("EnumType.js");
load("EvaluationCommon.js");
load("Evaluator.js");
load("ExpressionFinder.js");
@@ -76,6 +80,7 @@
load("FlattenProtocolExtends.js");
load("FloatLiteral.js");
load("FloatLiteralType.js");
+load("FoldConstexprs.js");
load("ForLoop.js");
load("Func.js");
load("FuncDef.js");
@@ -134,6 +139,7 @@
load("StructLayoutBuilder.js");
load("StructType.js");
load("Substitution.js");
+load("SynthesizeEnumFunctions.js");
load("SynthesizeStructAccessors.js");
load("TypeDef.js");
load("TypeDefResolver.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -79,6 +79,56 @@
}
}
+ visitEnumType(node)
+ {
+ node.baseType.visit(this);
+
+ let baseType = node.baseType.unifyNode;
+
+ if (!baseType.isInt)
+ throw new WTypeError(node.origin.originString, "Base type of enum is not an integer: " + node.baseType);
+
+ for (let member of node.members) {
+ if (!member.value)
+ continue;
+
+ let memberType = member.value.visit(this);
+ if (!baseType.equalsWithCommit(memberType))
+ throw new WTypeError(member.origin.originString, "Type of enum member " + member.value.name + " does not patch enum base type (member type is " + memberType + ", enum base type is " + node.baseType + ")");
+ }
+
+ let nextValue = baseType.defaultValue;
+ for (let member of node.members) {
+ if (member.value) {
+ nextValue = baseType.successorValue(member.value.unifyNode.valueForSelectedType);
+ continue;
+ }
+
+ member.value = baseType.createLiteral(member.origin, nextValue);
+ nextValue = baseType.successorValue(nextValue);
+ }
+
+ let memberArray = Array.from(node.members);
+ for (let i = 0; i < memberArray.length; ++i) {
+ let member = memberArray[i];
+ for (let j = i + 1; j < memberArray.length; ++j) {
+ let otherMember = memberArray[j];
+ if (baseType.valuesEqual(member.value.unifyNode.valueForSelectedType, otherMember.value.unifyNode.valueForSelectedType))
+ throw new WTypeError(otherMember.origin.originString, "Duplicate enum member value (" + member.name + " has " + member.value + " while " + otherMember.name + " has " + otherMember.value + ")");
+ }
+ }
+
+ let foundZero = false;
+ for (let member of node.members) {
+ if (baseType.valuesEqual(member.value.unifyNode.valueForSelectedType, baseType.defaultValue)) {
+ foundZero = true;
+ break;
+ }
+ }
+ if (!foundZero)
+ throw new WTypeError(node.origin.originString, "Enum does not have a member with the value zero");
+ }
+
_checkTypeArguments(origin, typeParameters, typeArguments)
{
for (let i = 0; i < typeParameters.length; ++i) {
@@ -345,6 +395,11 @@
{
return this._program.intrinsics.bool;
}
+
+ visitEnumLiteral(node)
+ {
+ return node.member.enumType;
+ }
_requireBool(_expression_)
{
Added: trunk/Tools/WebGPUShadingLanguageRI/ConstexprFolder.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/ConstexprFolder.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/ConstexprFolder.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -0,0 +1,50 @@
+/*
+ * 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";
+
+// NOTE: This doesn't let you negate constexpr variables. I think that's probably OK for now, but we should
+// fix that eventually.
+// https://bugs.webkit.org/show_bug.cgi?id=177121
+
+class ConstexprFolder extends Visitor {
+ visitCallExpression(node)
+ {
+ super.visitCallExpression(node);
+
+ if (node.name == "operator-"
+ && !node.typeArguments.length
+ && node.argumentList.length == 1
+ && node.argumentList[0].unifyNode.isConstexpr
+ && node.argumentList[0].unifyNode.negConstexpr) {
+ node.become(node.argumentList[0].unifyNode.negConstexpr(node.origin));
+ return;
+ }
+ }
+
+ visitTypeOrVariableRef(node)
+ {
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/CreateLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -42,9 +42,31 @@
}
get value() { return this._value; }
+
+ // This is necessary because once we support int64, we'll need that to be represented as an object
+ // rather than as a primitive. Then we'll need to convert.
+ get valueForSelectedType()
+ {
+ let type = this.type.type.unifyNode;
+ if (!type)
+ throw new Error("Cannot get type for " + this);
+ let func = type["formatValueFrom" + config.literalClassName];
+ if (!func)
+ throw new Error("Cannot get function to format type for " + config.literalClassName + " from " + type);
+ return func.call(type, this.value);
+ }
+
get isConstexpr() { return true; }
get isLiteral() { return true; }
+ get negConstexpr()
+ {
+ if (!config.negConstexpr)
+ return null;
+
+ return () => config.negConstexpr.call(this);
+ }
+
unifyImpl(unificationContext, other)
{
if (!(other instanceof GenericLiteral))
Modified: trunk/Tools/WebGPUShadingLanguageRI/DoubleLiteral.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/DoubleLiteral.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/DoubleLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -25,8 +25,14 @@
"use strict";
let DoubleLiteral = createLiteral({
+ literalClassName: "DoubleLiteral",
preferredTypeName: "double",
+ negConstexpr(origin)
+ {
+ return new IntLiteral(origin, -this.value);
+ },
+
createType(origin, value)
{
return new DoubleLiteralType(origin, value);
Modified: trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -98,6 +98,11 @@
node.ePtr = EPtr.box();
}
+ visitEnumLiteral(node)
+ {
+ node.ePtr = EPtr.box();
+ }
+
visitLogicalNot(node)
{
node.ePtr = EPtr.box();
Added: trunk/Tools/WebGPUShadingLanguageRI/EnumLiteral.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/EnumLiteral.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/EnumLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -0,0 +1,49 @@
+/*
+ * 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 EnumLiteral extends _expression_ {
+ constructor(origin, member)
+ {
+ super(origin);
+ this._member = member;
+ }
+
+ get member() { return this._member; }
+ get type() { return this.member.enumType; }
+ get isConstexpr() { return true; }
+
+ unifyImpl(unificationContext, other)
+ {
+ if (!(other instanceof EnumLiteral))
+ return false;
+ return this.member == other.member;
+ }
+
+ toString()
+ {
+ return this.member.enumType.name + "." + this.member.name;
+ }
+}
Added: trunk/Tools/WebGPUShadingLanguageRI/EnumMember.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/EnumMember.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/EnumMember.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -0,0 +1,46 @@
+/*
+ * 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 EnumMember extends Node {
+ constructor(origin, name, value)
+ {
+ super();
+ this._origin = origin;
+ this._name = name;
+ this.value = value;
+ }
+
+ get origin() { return this._origin; }
+ get name() { return this._name; }
+
+ toString()
+ {
+ let result = this.name;
+ if (this.value)
+ result += " = " + this.value;
+ return result;
+ }
+}
Added: trunk/Tools/WebGPUShadingLanguageRI/EnumType.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/EnumType.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/EnumType.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -0,0 +1,68 @@
+/*
+ * 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 EnumType extends Type {
+ constructor(origin, name, baseType)
+ {
+ super();
+ this._origin = origin;
+ this._name = name;
+ this._baseType = baseType;
+ this._members = new Map();
+ }
+
+ add(member)
+ {
+ if (this._members.has(member.name))
+ throw new WTypeError(member.origin.originString, "Duplicate enum member name: " + member.name);
+ member.enumType = this;
+ this._members.set(member.name, member);
+ }
+
+ get origin() { return this._origin; }
+ get name() { return this._name; }
+ get baseType() { return this._baseType; }
+
+ get memberNames() { return this._members.keys(); }
+ memberByName(name) { return this._members.get(name); }
+ get members() { return this._members.values(); }
+ get memberMap() { return this._members; }
+
+ get isPrimitive() { return true; }
+
+ populateDefaultValue(buffer, offset)
+ {
+ this.baseType.populateDefaultValue(buffer, offset);
+ }
+
+ get size() { return this.baseType.size; }
+
+ toString()
+ {
+ return "enum " + this.name + " : " + this.baseType + " { " + Array.from(this.members).join(",") + " }";
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -147,7 +147,7 @@
visitGenericLiteral(node)
{
- return node.ePtr.box(node.value);
+ return node.ePtr.box(node.valueForSelectedType);
}
visitNullLiteral(node)
@@ -159,6 +159,11 @@
{
return node.ePtr.box(node.value);
}
+
+ visitEnumLiteral(node)
+ {
+ return node.ePtr.box(node.member.value.unifyNode.valueForSelectedType);
+ }
visitLogicalNot(node)
{
Modified: trunk/Tools/WebGPUShadingLanguageRI/FloatLiteral.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/FloatLiteral.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/FloatLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -25,8 +25,14 @@
"use strict";
let FloatLiteral = createLiteral({
+ literalClassName: "FloatLiteral",
preferredTypeName: "float",
+ negConstexpr(origin)
+ {
+ return new IntLiteral(origin, -this.value);
+ },
+
createType(origin, value)
{
return new FloatLiteralType(origin, value);
Added: trunk/Tools/WebGPUShadingLanguageRI/FoldConstexprs.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/FoldConstexprs.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/FoldConstexprs.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -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 foldConstexprs(program)
+{
+ program.visit(new ConstexprFolder());
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -25,8 +25,14 @@
"use strict";
let IntLiteral = createLiteral({
+ literalClassName: "IntLiteral",
preferredTypeName: "int",
+ negConstexpr(origin)
+ {
+ return new IntLiteral(origin, (-this.value) | 0);
+ },
+
createType(origin, value)
{
return new IntLiteralType(origin, value);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -69,7 +69,13 @@
type.isSigned = true;
type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
+ type.successorValue = value => (value + 1) | 0;
+ type.valuesEqual = (a, b) => a === b;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value | 0;
+ type.formatValueFromUintLiteral = value => value | 0;
});
this._map.set(
@@ -81,7 +87,13 @@
type.isSigned = false;
type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
+ type.successorValue = value => (value + 1) >>> 0;
+ type.valuesEqual = (a, b) => a === b;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value >>> 0;
+ type.formatValueFromUintLiteral = value => value >>> 0;
});
this._map.set(
@@ -93,6 +105,10 @@
type.isNumber = true;
type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value;
+ type.formatValueFromUintLiteral = value => value;
+ type.formatValueFromFloatLiteral = value => Math.fround(value);
+ type.formatValueFromDoubleLiteral = value => Math.fround(value);
});
this._map.set(
@@ -104,6 +120,10 @@
type.isNumber = true;
type.canRepresent = value => true;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value;
+ type.formatValueFromUintLiteral = value => value;
+ type.formatValueFromFloatLiteral = value => value;
+ type.formatValueFromDoubleLiteral = value => value;
});
this._map.set(
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -255,6 +255,18 @@
visitDotExpression(node)
{
+ // This could be a reference to an enum. Let's resolve that now.
+ if (node.struct instanceof VariableRef) {
+ let enumType = this._nameContext.get(Type, node.struct.name);
+ if (enumType && enumType instanceof EnumType) {
+ let enumMember = enumType.memberByName(node.fieldName);
+ if (!enumMember)
+ throw new WTypeError(node.origin.originString, "Enum " + enumType.name + " does not have a member named " + node.fieldName);
+ node.become(new EnumLiteral(node.origin, enumMember));
+ return;
+ }
+ }
+
this._handlePropertyAccess(node);
super.visitDotExpression(node);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -227,7 +227,13 @@
function parseConstexpr()
{
- return parseTerm();
+ let token;
+ if (token = tryConsume("-"))
+ return new CallExpression(token, "operator" + token.text, [], [parseTerm()]);
+ let left = parseTerm();
+ if (token = tryConsume("."))
+ left = new DotExpression(token, left, consumeKind("identifier").text);
+ return left;
}
function parseTypeArguments()
@@ -396,12 +402,17 @@
function parsePossibleSuffix()
{
- if (isCallExpression())
- return parseCallExpression();
+ let acceptableOperators = ["++", "--", ".", "->", "["];
+ let limitedOperators = [".", "->", "["];
+ let left;
+ if (isCallExpression()) {
+ left = parseCallExpression();
+ acceptableOperators = limitedOperators;
+ } else
+ left = parseTerm();
- let left = parseTerm();
let token;
- while (token = tryConsume("++", "--", ".", "->", "[")) {
+ while (token = tryConsume(...acceptableOperators)) {
switch (token.text) {
case "++":
case "--":
@@ -422,6 +433,7 @@
default:
throw new Error("Bad token: " + token);
}
+ acceptableOperators = limitedOperators;
}
return left;
}
@@ -931,6 +943,35 @@
return result;
}
+ function parseEnumMember()
+ {
+ let name = consumeKind("identifier");
+ let value = null;
+ if (tryConsume("="))
+ value = parseConstexpr();
+ return new EnumMember(name, name.text, value);
+ }
+
+ function parseEnumType()
+ {
+ consume("enum");
+ let name = consumeKind("identifier");
+ let baseType;
+ if (tryConsume(":"))
+ baseType = parseType();
+ else
+ baseType = new TypeRef(name, "int", []);
+ consume("{");
+ let result = new EnumType(name, name.text, baseType);
+ while (!test("}")) {
+ result.add(parseEnumMember());
+ if (!tryConsume(","))
+ break;
+ }
+ consume("}");
+ return result;
+ }
+
for (;;) {
let token = lexer.peek();
if (!token)
@@ -946,7 +987,7 @@
else if (token.text == "struct")
program.add(parseStructType());
else if (token.text == "enum")
- program.add(parseEnum());
+ program.add(parseEnumType());
else if (token.text == "protocol")
program.add(parseProtocolDecl());
else
Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -35,6 +35,7 @@
let program = cloneProgram(standardProgram);
parse(program, origin, "user", lineNumberOffset, text);
+ foldConstexprs(program);
let nameResolver = createNameResolver(program);
resolveNamesInTypes(program, nameResolver);
resolveNamesInProtocols(program, nameResolver);
@@ -43,6 +44,7 @@
// FIXME: Need to verify that structre are not cyclic.
// https://bugs.webkit.org/show_bug.cgi?id=177044
synthesizeStructAccessors(program);
+ synthesizeEnumFunctions(program);
resolveNamesInFunctions(program, nameResolver);
resolveTypeDefsInFunctions(program);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -59,6 +59,7 @@
visitStructType(node) { return node; }
visitConstexprTypeParameter(node) { return node; }
visitProtocolDecl(node) { return node; }
+ visitEnumType(node) { return node; }
// This is almost wrong. We instantiate Func in Substitution in ProtocolDecl. Then, we end up
// not rewriting type variables. I think that just works because not rewriting them there is OK.
@@ -141,6 +142,18 @@
return new Field(node.origin, node.name, node.type.visit(this));
}
+ visitEnumMember(node)
+ {
+ return new EnumMember(node.origin, node.name, node.value.visit(this));
+ }
+
+ visitEnumLiteral(node)
+ {
+ let result = new EnumLiteral(node.origin, node.member);
+ result.ePtr = node.ePtr;
+ return result;
+ }
+
visitReferenceType(node)
{
return new node.constructor(node.rogiin, node.addressSpace, node.elementType.visit(this));
Modified: trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -109,5 +109,13 @@
{
return new TypeOrVariableRef(node.origin, node.name);
}
+
+ visitEnumType(node)
+ {
+ let result = new EnumType(node.origin, node.name, node.baseType.visit(this));
+ for (let member of node.members)
+ result.add(member);
+ return result;
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/StructType.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/StructType.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/StructType.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -43,6 +43,7 @@
}
get name() { return this._name; }
+ get origin() { return this._origin; }
get typeParameters() { return this._typeParameters; }
get fieldNames() { return this._fields.keys(); }
@@ -64,7 +65,7 @@
if (typeArguments) {
if (typeArguments.length != this.typeParameters.length)
- throw new WTypeError(origin.originString, "Wrong number of type arguments to instantiation");
+ throw new WTypeError(this.origin.originString, "Wrong number of type arguments to instantiation");
if (!typeArguments.length)
return this;
Added: trunk/Tools/WebGPUShadingLanguageRI/SynthesizeEnumFunctions.js (0 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/SynthesizeEnumFunctions.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/SynthesizeEnumFunctions.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -0,0 +1,68 @@
+/*
+ * 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 synthesizeEnumFunctions(program)
+{
+ for (let type of program.types.values()) {
+ if (!(type instanceof EnumType))
+ continue;
+
+ let nativeFunc;
+ let isCast = false;
+ let shaderType;
+
+ nativeFunc = new NativeFunc(
+ type.origin, "operator==", new TypeRef(type.origin, "bool", []), [],
+ [
+ new FuncParameter(type.origin, null, new TypeRef(type.origin, type.name, [])),
+ new FuncParameter(type.origin, null, new TypeRef(type.origin, type.name, []))
+ ],
+ isCast, shaderType);
+ nativeFunc.implementation = ([left, right]) => EPtr.box(left.loadValue() == right.loadValue());
+ program.add(nativeFunc);
+
+ nativeFunc = new NativeFunc(
+ type.origin, "operator.value", type.baseType.visit(new Rewriter()), [],
+ [new FuncParameter(type.origin, null, new TypeRef(type.origin, type.name, []))],
+ isCast, shaderType);
+ nativeFunc.implementation = ([value]) => value;
+ program.add(nativeFunc);
+
+ nativeFunc = new NativeFunc(
+ type.origin, "operator cast", type.baseType.visit(new Rewriter()), [],
+ [new FuncParameter(type.origin, null, new TypeRef(type.origin, type.name, []))],
+ isCast, shaderType);
+ nativeFunc.implementation = ([value]) => value;
+ program.add(nativeFunc);
+
+ nativeFunc = new NativeFunc(
+ type.origin, "operator cast", new TypeRef(type.origin, type.name, []), [],
+ [new FuncParameter(type.origin, null, type.baseType.visit(new Rewriter()))],
+ isCast, shaderType);
+ nativeFunc.implementation = ([value]) => value;
+ program.add(nativeFunc);
+ }
+}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-19 03:44:25 UTC (rev 222200)
@@ -33,6 +33,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -45,6 +46,9 @@
<script src=""
<script src=""
<script src=""
+<script src=""
+<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -53,6 +57,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -112,6 +117,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -101,6 +101,14 @@
checkNumber(program, result, expected);
}
+function checkEnum(program, result, expected)
+{
+ if (!(result.type instanceof EnumType))
+ throw new Error("Wrong result type; result: " + result);
+ if (result.value != expected)
+ throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
+}
+
function checkUint(program, result, expected)
{
if (!result.type.equals(program.intrinsics.uint32))
@@ -3894,6 +3902,281 @@
checkBool(program, callFunction(program, "food6", [], []), false);
}
+function TEST_simpleEnum()
+{
+ let program = doPrep(`
+ enum Foo {
+ War,
+ Famine,
+ Pestilence,
+ Death
+ }
+ Foo war()
+ {
+ return Foo.War;
+ }
+ Foo famine()
+ {
+ return Foo.Famine;
+ }
+ Foo pestilence()
+ {
+ return Foo.Pestilence;
+ }
+ Foo death()
+ {
+ return Foo.Death;
+ }
+ bool equals(Foo a, Foo b)
+ {
+ return a == b;
+ }
+ bool notEquals(Foo a, Foo b)
+ {
+ return a != b;
+ }
+ bool testSimpleEqual()
+ {
+ return equals(Foo.War, Foo.War);
+ }
+ bool testAnotherEqual()
+ {
+ return equals(Foo.Pestilence, Foo.Pestilence);
+ }
+ bool testNotEqual()
+ {
+ return equals(Foo.Famine, Foo.Death);
+ }
+ bool testSimpleNotEqual()
+ {
+ return notEquals(Foo.War, Foo.War);
+ }
+ bool testAnotherNotEqual()
+ {
+ return notEquals(Foo.Pestilence, Foo.Pestilence);
+ }
+ bool testNotNotEqual()
+ {
+ return notEquals(Foo.Famine, Foo.Death);
+ }
+ int intWar()
+ {
+ return int(war());
+ }
+ int intFamine()
+ {
+ return int(famine());
+ }
+ int intPestilence()
+ {
+ return int(pestilence());
+ }
+ int intDeath()
+ {
+ return int(death());
+ }
+ int warValue()
+ {
+ return war().value;
+ }
+ int famineValue()
+ {
+ return famine().value;
+ }
+ int pestilenceValue()
+ {
+ return pestilence().value;
+ }
+ int deathValue()
+ {
+ return death().value;
+ }
+ int warValueLiteral()
+ {
+ return Foo.War.value;
+ }
+ int famineValueLiteral()
+ {
+ return Foo.Famine.value;
+ }
+ int pestilenceValueLiteral()
+ {
+ return Foo.Pestilence.value;
+ }
+ int deathValueLiteral()
+ {
+ return Foo.Death.value;
+ }
+ Foo intWarBackwards()
+ {
+ return Foo(intWar());
+ }
+ Foo intFamineBackwards()
+ {
+ return Foo(intFamine());
+ }
+ Foo intPestilenceBackwards()
+ {
+ return Foo(intPestilence());
+ }
+ Foo intDeathBackwards()
+ {
+ return Foo(intDeath());
+ }
+ `);
+ checkEnum(program, callFunction(program, "war", [], []), 0);
+ checkEnum(program, callFunction(program, "famine", [], []), 1);
+ checkEnum(program, callFunction(program, "pestilence", [], []), 2);
+ checkEnum(program, callFunction(program, "death", [], []), 3);
+ checkBool(program, callFunction(program, "testSimpleEqual", [], []), true);
+ checkBool(program, callFunction(program, "testAnotherEqual", [], []), true);
+ checkBool(program, callFunction(program, "testNotEqual", [], []), false);
+ checkBool(program, callFunction(program, "testSimpleNotEqual", [], []), false);
+ checkBool(program, callFunction(program, "testAnotherNotEqual", [], []), false);
+ checkBool(program, callFunction(program, "testNotNotEqual", [], []), true);
+ checkInt(program, callFunction(program, "intWar", [], []), 0);
+ checkInt(program, callFunction(program, "intFamine", [], []), 1);
+ checkInt(program, callFunction(program, "intPestilence", [], []), 2);
+ checkInt(program, callFunction(program, "intDeath", [], []), 3);
+ checkInt(program, callFunction(program, "warValue", [], []), 0);
+ checkInt(program, callFunction(program, "famineValue", [], []), 1);
+ checkInt(program, callFunction(program, "pestilenceValue", [], []), 2);
+ checkInt(program, callFunction(program, "deathValue", [], []), 3);
+ checkInt(program, callFunction(program, "warValueLiteral", [], []), 0);
+ checkInt(program, callFunction(program, "famineValueLiteral", [], []), 1);
+ checkInt(program, callFunction(program, "pestilenceValueLiteral", [], []), 2);
+ checkInt(program, callFunction(program, "deathValueLiteral", [], []), 3);
+ checkEnum(program, callFunction(program, "intWarBackwards", [], []), 0);
+ checkEnum(program, callFunction(program, "intFamineBackwards", [], []), 1);
+ checkEnum(program, callFunction(program, "intPestilenceBackwards", [], []), 2);
+ checkEnum(program, callFunction(program, "intDeathBackwards", [], []), 3);
+}
+
+function TEST_enumWithManualValues()
+{
+ let program = doPrep(`
+ enum Foo {
+ War = 72,
+ Famine = 0,
+ Pestilence = 23,
+ Death = -42
+ }
+ Foo war()
+ {
+ return Foo.War;
+ }
+ Foo famine()
+ {
+ return Foo.Famine;
+ }
+ Foo pestilence()
+ {
+ return Foo.Pestilence;
+ }
+ Foo death()
+ {
+ return Foo.Death;
+ }
+ `);
+ checkEnum(program, callFunction(program, "war", [], []), 72);
+ checkEnum(program, callFunction(program, "famine", [], []), 0);
+ checkEnum(program, callFunction(program, "pestilence", [], []), 23);
+ checkEnum(program, callFunction(program, "death", [], []), -42);
+}
+
+function TEST_enumWithoutZero()
+{
+ checkFail(
+ () => doPrep(`
+ enum Foo {
+ War = 72,
+ Famine = 64,
+ Pestilence = 23,
+ Death = -42
+ }
+ `),
+ e => e instanceof WTypeError);
+}
+
+function TEST_enumDuplicates()
+{
+ checkFail(
+ () => doPrep(`
+ enum Foo {
+ War = -42,
+ Famine = 0,
+ Pestilence = 23,
+ Death = -42
+ }
+ `),
+ e => e instanceof WTypeError);
+}
+
+function TEST_enumWithSomeManualValues()
+{
+ let program = doPrep(`
+ enum Foo {
+ War = 72,
+ Famine,
+ Pestilence = 0,
+ Death
+ }
+ Foo war()
+ {
+ return Foo.War;
+ }
+ Foo famine()
+ {
+ return Foo.Famine;
+ }
+ Foo pestilence()
+ {
+ return Foo.Pestilence;
+ }
+ Foo death()
+ {
+ return Foo.Death;
+ }
+ `);
+ checkEnum(program, callFunction(program, "war", [], []), 72);
+ checkEnum(program, callFunction(program, "famine", [], []), 73);
+ checkEnum(program, callFunction(program, "pestilence", [], []), 0);
+ checkEnum(program, callFunction(program, "death", [], []), 1);
+}
+
+function TEST_enumConstexprGenericFunction()
+{
+ let program = doPrep(`
+ enum Axis { X, Y }
+ int foo<Axis axis>() { return int(axis); }
+ int testX() { return foo<Axis.X>(); }
+ int testY() { return foo<Axis.Y>(); }
+ `);
+ checkInt(program, callFunction(program, "testX", [], []), 0);
+ checkInt(program, callFunction(program, "testY", [], []), 1);
+}
+
+function TEST_enumConstexprGenericStruct()
+{
+ let program = doPrep(`
+ enum Axis { X, Y }
+ struct Foo<Axis axis> { }
+ int foo<Axis axis>(Foo<axis>) { return int(axis); }
+ int testX()
+ {
+ Foo<Axis.X> f;
+ return foo(f);
+ }
+ int testY()
+ {
+ Foo<Axis.Y> f;
+ return foo(f);
+ }
+ `);
+ checkInt(program, callFunction(program, "testX", [], []), 0);
+ checkInt(program, callFunction(program, "testY", [], []), 1);
+}
+
let filter = /.*/; // run everything by default
if (this["arguments"]) {
for (let i = 0; i < arguments.length; i++) {
Modified: trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/UintLiteral.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -25,8 +25,14 @@
"use strict";
let UintLiteral = createLiteral({
+ literalClassName: "UintLiteral",
preferredTypeName: "uint",
+ negConstexpr(origin)
+ {
+ return new UintLiteral(origin, (-this.value) >>> 0);
+ },
+
createType(origin, value)
{
return new UintLiteralType(origin, value);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (222199 => 222200)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-19 03:19:22 UTC (rev 222199)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-19 03:44:25 UTC (rev 222200)
@@ -141,6 +141,22 @@
node.type.visit(this);
}
+ visitEnumType(node)
+ {
+ node.baseType.visit(this);
+ for (let member of node.members)
+ member.visit(this);
+ }
+
+ visitEnumMember(node)
+ {
+ Node.visit(node.value, this);
+ }
+
+ visitEnumLiteral(node)
+ {
+ }
+
visitElementalType(node)
{
node.elementType.visit(this);