Diff
Modified: trunk/Tools/ChangeLog (221633 => 221634)
--- trunk/Tools/ChangeLog 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/ChangeLog 2017-09-05 21:11:59 UTC (rev 221634)
@@ -1,3 +1,84 @@
+2017-09-05 Myles C. Maxfield <mmaxfi...@apple.com>
+
+ WSL should support the bool type
+ https://bugs.webkit.org/show_bug.cgi?id=176285
+
+ Reviewed by Filip Pizlo.
+
+ Very similar to the int and uint types. This patch also adds support for a logical negation _expression_ "!x".
+ This patch also reverts the ability of the program author to create their own "operator!()", and instead
+ adds the ability of the program author to create their own "operator bool()". The code is generic, so
+ programmers can make two arbitrary types Foo and Bar, and implement a "operator Bar(Foo)." The logical
+ negation _expression_ is a built-in, and requires its argument be a bool.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/BoolLiteral.js: Copied from Tools/WebGPUShadingLanguageRI/NativeFunc.js.
+ (BoolLiteral):
+ (BoolLiteral.prototype.get value):
+ (BoolLiteral.prototype.get isConstexpr):
+ (BoolLiteral.prototype.toString):
+ * WebGPUShadingLanguageRI/Checker.js:
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype.visitBoolLiteral):
+ (Evaluator.prototype.visitLogicalNot):
+ * WebGPUShadingLanguageRI/Func.js:
+ (Func):
+ (Func.prototype.get isCast):
+ (Func.prototype.toDeclString):
+ * WebGPUShadingLanguageRI/FuncDef.js:
+ (FuncDef):
+ (FuncDef.prototype.get body):
+ (FuncDef.prototype.rewrite):
+ * WebGPUShadingLanguageRI/Intrinsics.js:
+ (Intrinsics):
+ * WebGPUShadingLanguageRI/Lexer.js:
+ (Lexer.prototype.next):
+ (Lexer):
+ * WebGPUShadingLanguageRI/LogicalNot.js: Copied from Tools/WebGPUShadingLanguageRI/NativeFunc.js.
+ (LogicalNot):
+ (LogicalNot.prototype.get operand):
+ (LogicalNot.prototype.toString):
+ * WebGPUShadingLanguageRI/NativeFunc.js:
+ (NativeFunc):
+ * WebGPUShadingLanguageRI/Parse.js:
+ (parseTerm):
+ (parsePossiblePrefix):
+ (parsePossibleRelationalEquality):
+ (parseFuncName):
+ (parseOperatorFuncDefValues):
+ (parseNonOperatorFuncDefValues):
+ (parseGenericFuncDefValues):
+ (parseFuncDecl):
+ (parseProtocolFuncDecl):
+ (parseFuncDef):
+ (parseNative):
+ (parse):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitBoolLiteral):
+ (Rewriter.prototype.visitLogicalNot):
+ (Rewriter):
+ * WebGPUShadingLanguageRI/StandardLibrary.js:
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (makeUInt):
+ (makeBool):
+ (checkUInt):
+ (checkBool):
+ (TEST_literalBool):
+ (TEST_identityBool):
+ (TEST_intSimpleMath):
+ (TEST_uintSimpleMath):
+ (TEST_equality):
+ (TEST_logicalNegation):
+ (TEST_notEquality):
+ (TEST_equalityTypeFailure):
+ (TEST_add1): Deleted.
+ * WebGPUShadingLanguageRI/TypeDefResolver.js:
+ (TypeDefResolver.prototype.visitFuncDef):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitBoolLiteral):
+ (Visitor.prototype.visitLogicalNot):
+
2017-09-05 Matt Lewis <jlew...@apple.com>
Unreviewed, rolling out r221603.
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -37,6 +37,7 @@
load("ArrayType.js");
load("Assignment.js");
load("Block.js");
+load("BoolLiteral.js");
load("CallAssignment.js");
load("CallExpression.js");
load("CallFunction.js");
@@ -70,6 +71,7 @@
load("Lexer.js");
load("LexerToken.js");
load("LiteralTypeChecker.js");
+load("LogicalNot.js");
load("MakePtrExpression.js");
load("NameContext.js");
load("NameResolver.js");
Copied: trunk/Tools/WebGPUShadingLanguageRI/BoolLiteral.js (from rev 221633, trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js) (0 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/BoolLiteral.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/BoolLiteral.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -0,0 +1,42 @@
+/*
+ * 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 BoolLiteral extends _expression_ {
+ constructor(origin, value)
+ {
+ super(origin);
+ this._value = value;
+ }
+
+ get value() { return this._value; }
+ get isConstexpr() { return true; }
+
+ toString()
+ {
+ return "" + this._value;
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -211,6 +211,21 @@
return node.type;
}
+ visitBoolLiteral(node)
+ {
+ return this._program.intrinsics.bool;
+ }
+
+ visitLogicalNot(node)
+ {
+ let resultType = node.operand.visit(this);
+ if (!resultType)
+ throw new Error("Trying to negate something with no type: " + node.value);
+ if (!resultType.equals(this._program.intrinsics.bool))
+ throw new WError("Trying to negate something that isn't a bool: " + node.value);
+ return this._program.intrinsics.bool;
+ }
+
visitCommaExpression(node)
{
let result = null;
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -141,6 +141,16 @@
return EPtr.box(null);
}
+ visitBoolLiteral(node)
+ {
+ return EPtr.box(node.value);
+ }
+
+ visitLogicalNot(node)
+ {
+ return EPtr.box(!node.operand.visit(this).loadValue());
+ }
+
visitCallExpression(node)
{
// We evaluate inlined ASTs, so this can only be a native call.
Modified: trunk/Tools/WebGPUShadingLanguageRI/Func.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Func.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Func.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -25,7 +25,7 @@
"use strict";
class Func extends Node {
- constructor(origin, name, returnType, typeParameters, parameters)
+ constructor(origin, name, returnType, typeParameters, parameters, isCast)
{
super();
this._origin = origin;
@@ -33,6 +33,7 @@
this._returnType = returnType;
this._typeParameters = typeParameters;
this._parameters = parameters;
+ this._isCast = isCast;
}
get origin() { return this._origin; }
@@ -41,12 +42,13 @@
get typeParameters() { return this._typeParameters; }
get parameters() { return this._parameters; }
get parameterTypes() { return this.parameters.map(parameter => parameter.type); }
+ get isCast() { return this._isCast; }
get kind() { return Func; }
toDeclString()
{
- return this.returnType + " " + this.name + "<" + this.typeParameters + ">(" + this.parameters + ")";
+ return (this.isCast ? "" : this.returnType + " ") + this.name + "<" + this.typeParameters + ">(" + this.parameters + ")";
}
toString()
Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -25,11 +25,13 @@
"use strict";
class FuncDef extends Func {
- constructor(origin, name, returnType, typeParameters, parameters, body)
+ constructor(origin, name, returnType, typeParameters, parameters, body, isCast)
{
- super(origin, name, returnType, typeParameters, parameters);
- this.body = body;
+ super(origin, name, returnType, typeParameters, parameters, isCast);
+ this._body = body;
}
+
+ get body() { return this._body; }
rewrite(rewriter)
{
@@ -37,7 +39,7 @@
throw new Error("Cannot rewrite an uninstantiated function");
this._returnType = this._returnType.visit(rewriter);
this._parameters = this._parameters.map(parameter => parameter.visit(rewriter));
- this.body = this.body.visit(rewriter);
+ this._body = this.body.visit(rewriter);
}
toString()
Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -92,6 +92,14 @@
type.canRepresent = value => true;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
});
+
+ this._map.set(
+ "native primitive type bool<>",
+ type => {
+ this.bool = type;
+ type.size = 1;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
+ });
this._map.set(
"native int operator+<>(int,int)",
@@ -100,6 +108,97 @@
EPtr.box((left.loadValue() + right.loadValue()) | 0);
});
+ this._map.set(
+ "native uint operator+<>(uint,uint)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() + right.loadValue()) >>> 0);
+ });
+
+ this._map.set(
+ "native int operator-<>(int,int)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() - right.loadValue()) | 0);
+ });
+
+ this._map.set(
+ "native uint operator-<>(uint,uint)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() - right.loadValue()) >>> 0);
+ });
+
+ this._map.set(
+ "native int operator*<>(int,int)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() * right.loadValue()) | 0);
+ });
+
+ this._map.set(
+ "native uint operator*<>(uint,uint)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() * right.loadValue()) >>> 0);
+ });
+
+ this._map.set(
+ "native int operator/<>(int,int)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() / right.loadValue()) | 0);
+ });
+
+ this._map.set(
+ "native uint operator/<>(uint,uint)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box((left.loadValue() / right.loadValue()) >>> 0);
+ });
+
+ 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==<>(bool,bool)",
+ func => {
+ func.implementation = ([left, right]) =>
+ EPtr.box(left.loadValue() == right.loadValue());
+ });
+
+ this._map.set(
+ "native operator int<>(int)",
+ func => {
+ func.implementation = ([value]) =>
+ EPtr.box(value.loadValue());
+ });
+
+ this._map.set(
+ "native operator uint<>(uint)",
+ func => {
+ func.implementation = ([value]) =>
+ EPtr.box(value.loadValue());
+ });
+
+ this._map.set(
+ "native operator bool<>(bool)",
+ func => {
+ func.implementation = ([value]) =>
+ EPtr.box(value.loadValue());
+ });
+
let arrayElementPtr = func => {
func.implementation = ([ref, index], node) => {
ref = ref.loadValue();
Modified: trunk/Tools/WebGPUShadingLanguageRI/Lexer.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Lexer.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Lexer.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -103,7 +103,7 @@
// FIXME: Make this do Unicode.
if (/^[^\d\W]\w*/.test(relevantText)) {
- if (["struct", "protocol", "typedef", "if", "else", "enum", "continue", "break", "switch", "case", "default", "for", "while", "do", "return", "sizeof", "constant", "device", "threadgroup", "thread", "operator", "null"].includes(RegExp.lastMatch))
+ if (["struct", "protocol", "typedef", "if", "else", "enum", "continue", "break", "switch", "case", "default", "for", "while", "do", "return", "sizeof", "constant", "device", "threadgroup", "thread", "operator", "null", "true", "false"].includes(RegExp.lastMatch))
return result("keyword");
return result("identifier");
}
@@ -118,7 +118,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/LogicalNot.js (from rev 221633, trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js) (0 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/LogicalNot.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/LogicalNot.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -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 LogicalNot extends _expression_ {
+ constructor(origin, operand)
+ {
+ super(origin);
+ this._operand = operand;
+ }
+
+ get operand() { return this._operand; }
+
+ toString()
+ {
+ return "!(" + this.operand + ")";
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/NativeFunc.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -25,9 +25,9 @@
"use strict";
class NativeFunc extends Func {
- constructor(origin, name, returnType, typeParameters, parameters)
+ constructor(origin, name, returnType, typeParameters, parameters, isCast = false)
{
- super(origin, name, returnType, typeParameters, parameters);
+ super(origin, name, returnType, typeParameters, parameters, isCast);
}
get isNative() { return true; }
Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -183,10 +183,10 @@
lexer.fail("Integer literal is not 32-bit unsigned integer");
return new UintLiteral(token, uintVersion);
}
- if (token = tryConsumeKind("doubleLiteral")) {
- token = consumeKind("doubleLiteral");
+ if (token = tryConsumeKind("doubleLiteral"))
return new DoubleLiteral(token, +token.text);
- }
+ if (token = tryConsume("true", "false"))
+ return new BoolLiteral(token, token.text == "true");
// FIXME: Need support for float literals and probably other literals too.
consume("(");
let result = parseExpression();
@@ -296,30 +296,6 @@
return new TypeDef(origin, name, typeParameters, type);
}
- function parseNative()
- {
- let origin = consume("native");
- let isType = lexer.backtrackingScope(() => {
- if (tryConsume("typedef"))
- return "normal";
- consume("primitive");
- consume("typedef");
- return "primitive";
- });
- if (isType) {
- let name = consumeKind("identifier");
- let parameters = parseTypeParameters();
- consume(";");
- return new NativeType(origin, name.text, isType == "primitive", parameters);
- }
- let returnType = parseType();
- let name = parseFuncName();
- let typeParameters = parseTypeParameters();
- let parameters = parseParameters();
- consume(";");
- return new NativeFunc(origin, name, returnType, typeParameters, parameters);
- }
-
function genericParseLeft(texts, nextParser, constructor)
{
let left = nextParser();
@@ -396,7 +372,7 @@
function parsePossiblePrefix()
{
let token;
- if (token = tryConsume("++", "--", "+", "-", "!", "~"))
+ if (token = tryConsume("++", "--", "+", "-", "~"))
return new CallAssignment(token, "operator" + token.text, parsePossiblePrefix());
if (token = tryConsume("^"))
return new DereferenceExpression(token, parsePossiblePrefix());
@@ -404,6 +380,8 @@
return new MakePtrExpression(token, parsePossiblePrefix());
if (token = tryConsume("@"))
return new MakeArrayRefExpression(token, parsePossiblePrefix());
+ if (token = tryConsume("!"))
+ return new LogicalNot(token, new CallExpression(token, "operator bool", [], [parsePossiblePrefix()]));
return parsePossibleSuffix();
}
@@ -434,7 +412,7 @@
(token, left, right) => {
let result = new CallExpression(token, "operator==", [], [left, right]);
if (token.text == "!=")
- result = new CallExpression(token, "operator!", [], [result]);
+ result = new LogicalNot(token, result);
return result;
});
}
@@ -629,32 +607,70 @@
function parseFuncName()
{
if (tryConsume("operator")) {
- let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "!", "==", "++", "--", "&");
- if (token.text != "&" || !tryConsume("["))
- return "operator" + token.text;
- consume("]");
- return "operator&[]";
+ let token = tryConsume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", "&");
+ if (token) {
+ if (token.text != "&" || !tryConsume("["))
+ return "operator" + token.text;
+ consume("]");
+ return "operator&[]";
+ }
+ let name = consumeKind("identifier");
+ return "operator " + name;
}
return consumeKind("identifier").text;
}
-
- function parseProtocolFuncDecl()
+
+ function parseOperatorFuncDefValues()
{
- let returnType = parseType();
- let name = parseFuncName();
+ let result = {};
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176316 Correctly handle the interaction between casting operators and complex types
+ let castType = consumeKind("identifier").text;
+ result.returnType = new TypeRef(name, castType, []);
+ result.name = "operator " + castType;
+ result.isCast = true;
+ return result;
+ }
+
+ function parseNonOperatorFuncDefValues()
+ {
+ let result = {};
+ result.returnType = parseType();
+ result.origin = result.returnType.origin;
+ result.name = parseFuncName();
+ result.isCast = false;
+ return result;
+ }
+
+ function parseGenericFuncDefValues()
+ {
+ let operatorToken = tryConsume("operator");
+ if (operatorToken) {
+ let result = parseOperatorFuncDefValues();
+ result.origin = operatorToken.origin;
+ return result;
+ }
+ return parseNonOperatorFuncDefValues();
+ }
+
+ function parseFuncDecl()
+ {
+ let values = parseGenericFuncDefValues();
let typeParameters = parseTypeParameters();
let parameters = parseParameters();
- return new ProtocolFuncDecl(returnType.origin, name, returnType, typeParameters, parameters);
+ return new Func(values.origin, values.name, values.returnType, typeParameters, parameters, values.isCast);
}
+
+ function parseProtocolFuncDecl()
+ {
+ let func = parseFuncDecl();
+ return new ProtocolFuncDecl(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
+ }
function parseFuncDef()
{
- let returnType = parseType();
- let name = parseFuncName();
- let typeParameters = parseTypeParameters();
- let parameters = parseParameters();
+ let func = parseFuncDecl();
let body = parseBlock();
- return new FuncDef(returnType.origin, name, returnType, typeParameters, parameters, body);
+ return new FuncDef(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, body, func.isCast);
}
function parseProtocolDecl()
@@ -692,6 +708,27 @@
return result;
}
+ function parseNative()
+ {
+ let origin = consume("native");
+ let isType = lexer.backtrackingScope(() => {
+ if (tryConsume("typedef"))
+ return "normal";
+ consume("primitive");
+ consume("typedef");
+ return "primitive";
+ });
+ if (isType) {
+ let name = consumeKind("identifier");
+ let parameters = parseTypeParameters();
+ consume(";");
+ return new NativeType(origin, name.text, isType == "primitive", parameters);
+ }
+ let func = parseFuncDecl();
+ consume(";");
+ return new NativeFunc(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
+ }
+
for (;;) {
let token = lexer.peek();
if (!token)
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -216,6 +216,11 @@
{
return node;
}
+
+ visitBoolLiteral(node)
+ {
+ return node;
+ }
visitNullLiteral(node)
{
@@ -258,5 +263,10 @@
node.parameters.map(parameter => parameter.visit(this)),
node.body.visit(this));
}
+
+ visitLogicalNot(node)
+ {
+ return new LogicalNot(node.origin, node.operand.visit(this));
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -35,6 +35,7 @@
native primitive typedef int32;
native primitive typedef uint32;
+native primitive typedef bool;
typedef int = int32;
typedef uint = uint32;
@@ -41,7 +42,21 @@
native primitive typedef double;
native int operator+(int, int);
+native uint operator+(uint, uint);
+native int operator-(int, int);
+native uint operator-(uint, uint);
+native int operator*(int, int);
+native uint operator*(uint, uint);
+native int operator/(int, int);
+native uint operator/(uint, uint);
+native bool operator==(int, int);
+native bool operator==(uint, uint);
+native bool operator==(bool, bool);
+native operator int(int);
+native operator uint(uint);
+native operator bool(bool);
+
native thread T^ operator&[]<T>(thread T[], uint);
native threadgroup T^ operator&[]<T:primitive>(threadgroup T[], uint);
native device T^ operator&[]<T:primitive>(device T[], uint);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-05 21:11:59 UTC (rev 221634)
@@ -13,6 +13,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -43,9 +44,10 @@
<script src=""
<script src=""
<script src=""
-<script src=""
<script src=""
<script src=""
+<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -65,6 +65,16 @@
throw new Error("Wrong result: " + result + " (expected " + expected + ")");
}
+function makeUInt(program, value)
+{
+ return TypedValue.box(program.intrinsics.uint32, value);
+}
+
+function makeBool(program, value)
+{
+ return TypedValue.box(program.intrinsics.bool, value);
+}
+
function checkInt(program, result, expected)
{
if (!result.type.equals(program.intrinsics.int32))
@@ -72,6 +82,22 @@
checkNumber(program, result, expected);
}
+function checkUInt(program, result, expected)
+{
+ if (!result.type.equals(program.intrinsics.uint32))
+ throw new Error("Wrong result type; result: " + result);
+ if (result.value != expected)
+ throw new Error("Wrong result: " + result + " (expected " + expected + ")");
+}
+
+function checkBool(program, result, expected)
+{
+ if (!result.type.equals(program.intrinsics.bool))
+ throw new Error("Wrong result type; result: " + result);
+ if (result.value != expected)
+ throw new Error("Wrong result: " + result + " (expected " + expected + ")");
+}
+
function checkLexerToken(result, expectedIndex, expectedKind, expectedText)
{
if (result._index != expectedIndex)
@@ -96,6 +122,85 @@
}
}
+function TEST_literalBool() {
+ let program = doPrep("bool foo() { return true; }");
+ checkBool(program, callFunction(program, "foo", [], []), true);
+}
+
+function TEST_identityBool() {
+ let program = doPrep("bool foo(bool x) { return x; }");
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), false);
+}
+
+function TEST_intSimpleMath() {
+ let program = doPrep("int foo(int x, int y) { return x + y; }");
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 12);
+ program = doPrep("int foo(int x, int y) { return x - y; }");
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 2);
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 5), makeInt(program, 7)]), -2);
+ program = doPrep("int foo(int x, int y) { return x * y; }");
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), 35);
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -5)]), -35);
+ program = doPrep("int foo(int x, int y) { return x / y; }");
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 2)]), 3);
+ checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, -2)]), -3);
+}
+
+function TEST_uintSimpleMath() {
+ let program = doPrep("uint foo(uint x, uint y) { return x + y; }");
+ checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), 12);
+ program = doPrep("uint foo(uint x, uint y) { return x - y; }");
+ checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), 2);
+ checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 5), makeUInt(program, 7)]), 4294967294);
+ program = doPrep("uint foo(uint x, uint y) { return x * y; }");
+ checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), 35);
+ program = doPrep("uint foo(uint x, uint y) { return x / y; }");
+ checkUInt(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 2)]), 3);
+}
+
+function TEST_equality() {
+ let program = doPrep("bool foo(uint x, uint y) { return x == y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 7)]), true);
+ program = doPrep("bool foo(int x, int y) { return x == y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), true);
+ program = doPrep("bool foo(bool x, bool y) { return x == y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), true);
+}
+
+function TEST_logicalNegation()
+{
+ let program = doPrep("bool foo(bool x) { return !x; }");
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false)]), true);
+}
+
+function TEST_notEquality() {
+ let program = doPrep("bool foo(uint x, uint y) { return x != y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 5)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeUInt(program, 7), makeUInt(program, 7)]), false);
+ program = doPrep("bool foo(int x, int y) { return x != y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 5)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeInt(program, 7), makeInt(program, 7)]), false);
+ program = doPrep("bool foo(bool x, bool y) { return x != y; }");
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, true)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, false)]), true);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, false), makeBool(program, false)]), false);
+ checkBool(program, callFunction(program, "foo", [], [makeBool(program, true), makeBool(program, true)]), false);
+}
+
+function TEST_equalityTypeFailure()
+{
+ checkFail(
+ () => doPrep("bool foo(int x, uint y) { return x == y; }"),
+ (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1);
+}
+
function TEST_add1() {
let program = doPrep("int foo(int x) { return x + 1; }");
checkInt(program, callFunction(program, "foo", [], [makeInt(program, 42)]), 43);
Modified: trunk/Tools/WebGPUShadingLanguageRI/TypeDefResolver.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/TypeDefResolver.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeDefResolver.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -30,6 +30,15 @@
super();
this._visiting = new VisitingSet();
}
+
+ visitFuncDef(node)
+ {
+ if (node.isCast && node.returnType.type instanceof TypeDef) {
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176316 Correctly handle the interaction between casting operators and complex types
+ throw new Error("Casting operators don't work with typedefs.");
+ }
+ super.visitFuncDef(node);
+ }
visitTypeRef(node)
{
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (221633 => 221634)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-05 21:00:23 UTC (rev 221633)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-05 21:11:59 UTC (rev 221634)
@@ -233,6 +233,10 @@
node.type.visit(this);
}
+ visitBoolLiteral(node)
+ {
+ }
+
visitNullType(node)
{
if (node.type)
@@ -251,6 +255,11 @@
argument.visit(this);
}
}
+
+ visitLogicalNot(node)
+ {
+ node.operand.visit(this);
+ }
visitFunctionLikeBlock(node)
{