WebKit Bugzilla
Attachment 348994 Details for
Bug 189014
: [WHLSL] The parser is too slow
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-189014-20180905191036.patch (text/plain), 63.37 KB, created by
Myles C. Maxfield
on 2018-09-05 19:10:37 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2018-09-05 19:10:37 PDT
Size:
63.37 KB
patch
obsolete
>Subversion Revision: 235685 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 9bb48193bc143352d9944ffecf6d83441c6f1f49..257b9204775590a3928a1f5e18c466f3f5ddb5b4 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,88 @@ >+2018-09-05 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] The parser is too slow >+ https://bugs.webkit.org/show_bug.cgi?id=189014 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch includes three changes: >+ 1. Migrate from using try/catch to simply returning the WSyntaxError. This means that >+ each parser call has to check for this sentinel value. The lexer still can throw if >+ it encounters an unknown token or an unmatched "/*" token (which is rare). >+ 2. After removing try/catch, making the sentinel values not inherit from Error (the >+ Error constructor was taking lots of time) >+ 3. Previously, every time the parser failed (which is many times per expression) it was >+ running a regex over the entire source text to figure out where the error occurred. >+ Instead, we can preprocess the text string to find these line numbers ahead of time. >+ >+ Together, these make the parser 75x faster. Parsing the standard library goes from 2.5 >+ hours down to 2 minutes. Because it's now a reasonable length, this patch uncomments >+ the bulk of the standard library. >+ >+ * WebGPUShadingLanguageRI/All.js: >+ * WebGPUShadingLanguageRI/Lexer.js: >+ (Lexer): >+ (Lexer.prototype.lineNumberForIndex): >+ * WebGPUShadingLanguageRI/Parse.js: >+ (fail): >+ (backtrackingScope): >+ (testScope): >+ (genericConsume): >+ (consumeEndOfTypeArgs): >+ (parseTerm): >+ (parseConstexpr): >+ (parseTypeArguments): >+ (parseType.getAddressSpace): >+ (parseType): >+ (parseTypeDef): >+ (genericParseLeft): >+ (parseCallExpression.let.parseArguments): >+ (isCallExpression): >+ (parseSuffixOperator): >+ (parsePossibleSuffix): >+ (parsePreIncrement): >+ (parsePossiblePrefix): >+ (parsePossibleTernaryConditional): >+ (parsePossibleAssignment): >+ (parsePostIncrement): >+ (parseEffectfulExpression): >+ (genericParseCommaExpression): >+ (parseEffectfulStatement): >+ (parseReturn): >+ (parseBreak): >+ (parseContinue): >+ (parseIfStatement): >+ (parseWhile): >+ (parseFor): >+ (parseDo): >+ (parseVariableDecls): >+ (parseSwitchCase): >+ (parseSwitchStatement): >+ (parseStatement): >+ (parseBlockBody): >+ (parseBlock): >+ (parseParameter): >+ (parseFuncName): >+ (parseFuncDecl): >+ (parseFuncDef): >+ (parseField): >+ (parseStructType): >+ (parseNativeFunc): >+ (parseNative): >+ (parseRestrictedFuncDef): >+ (parseEnumMember): >+ (parseEnumType): >+ (parse): >+ * WebGPUShadingLanguageRI/SPIRV.html: >+ * WebGPUShadingLanguageRI/StandardLibrary.js: >+ (let.standardLibrary): >+ * WebGPUShadingLanguageRI/Test.html: >+ * WebGPUShadingLanguageRI/Test.js: >+ (checkFail.doPrep): Deleted. >+ * WebGPUShadingLanguageRI/WLexicalError.js: Added. >+ (WLexicalError): >+ * WebGPUShadingLanguageRI/index.html: >+ > 2018-09-05 Woodrow Wang <woodrow_wang@apple.com> > > Added runtime feature flag for web API statistics >diff --git a/Tools/WebGPUShadingLanguageRI/All.js b/Tools/WebGPUShadingLanguageRI/All.js >index 90fc8413a65122446bf01fd967dd65139a0f87e9..0a5885161a403d09aeaa1fe5e1043adfe612565f 100644 >--- a/Tools/WebGPUShadingLanguageRI/All.js >+++ b/Tools/WebGPUShadingLanguageRI/All.js >@@ -168,6 +168,7 @@ load("VariableDecl.js"); > load("VariableRef.js"); > load("VectorType.js"); > load("VisitingSet.js"); >+load("WLexicalError.js"); > load("WSyntaxError.js"); > load("WTrapError.js"); > load("WTypeError.js"); >diff --git a/Tools/WebGPUShadingLanguageRI/Lexer.js b/Tools/WebGPUShadingLanguageRI/Lexer.js >index 956dca336a2a9a3121a277285ae3db76dde72370..aca793cdbe238285d97c9c87265337373fec785c 100644 >--- a/Tools/WebGPUShadingLanguageRI/Lexer.js >+++ b/Tools/WebGPUShadingLanguageRI/Lexer.js >@@ -35,6 +35,14 @@ class Lexer { > this._text = text; > this._index = 0; > this._stack = []; >+ >+ this._lineNumbers = []; >+ let lineNumber = 1; >+ for (let i = 0; i < this._text.length; ++i) { >+ this._lineNumbers.push(lineNumber); >+ if (this._text[i] == '\n') >+ ++lineNumber; >+ } > } > > get lineNumber() >@@ -53,8 +61,7 @@ class Lexer { > > lineNumberForIndex(index) > { >- let matches = this._text.substring(0, index).match(/\n/g); >- return (matches ? matches.length : 0) + this._lineNumberOffset; >+ return this._lineNumbers[index] + this._lineNumberOffset; > } > > get state() { return {index: this._index, stack: this._stack.concat()}; } >@@ -166,35 +173,6 @@ class Lexer { > > fail(error) > { >- throw new WSyntaxError(this.originString, error); >- } >- >- backtrackingScope(callback) >- { >- let state = this.state; >- try { >- return callback(); >- } catch (e) { >- if (e instanceof WSyntaxError) { >- this.state = state; >- return null; >- } >- throw e; >- } >- } >- >- testScope(callback) >- { >- let state = this.state; >- try { >- callback(); >- return true; >- } catch (e) { >- if (e instanceof WSyntaxError) >- return false; >- throw e; >- } finally { >- this.state = state; >- } >+ throw new WLexicalError(this.originString, error); > } > } >diff --git a/Tools/WebGPUShadingLanguageRI/LexerToken.js b/Tools/WebGPUShadingLanguageRI/LexerToken.js >index 9e06ee68f72380ebbd6a605001f5a3f262812bf5..1440312cddd5f69a824c42790e7cdcde8c23705b 100644 >--- a/Tools/WebGPUShadingLanguageRI/LexerToken.js >+++ b/Tools/WebGPUShadingLanguageRI/LexerToken.js >@@ -70,7 +70,7 @@ class LexerToken { > > get originString() > { >- return this.origin + ":" + (this.lineNumber + 1); >+ return this.origin + ":" + this.lineNumber; > } > > toString() >diff --git a/Tools/WebGPUShadingLanguageRI/Parse.js b/Tools/WebGPUShadingLanguageRI/Parse.js >index ee4c980f3a1672b68a77ebb48525edd249443a53..4fb849d0cdf0d9da090f1c30131128b41351b9f1 100644 >--- a/Tools/WebGPUShadingLanguageRI/Parse.js >+++ b/Tools/WebGPUShadingLanguageRI/Parse.js >@@ -27,7 +27,7 @@ > function parse(program, origin, originKind, lineNumberOffset, text) > { > let lexer = new Lexer(origin, originKind, lineNumberOffset, text); >- >+ > // The hardest part of dealing with C-like languages is parsing variable declaration statements. > // Let's consider if this happens in WSL. Here are the valid statements in WSL that being with an > // identifier, if we assume that any expression can be a standalone statement. >@@ -61,32 +61,59 @@ function parse(program, origin, originKind, lineNumberOffset, text) > // pointers means that we can still allow function call statements - unlike in C, those cannot > // have arbitrary expressions as the callee. The remaining two problems are solved by > // backtracking. In all other respects, this is a simple recursive descent parser. >- >+ >+ function fail(error) >+ { >+ return new WSyntaxError(lexer.originString, error); >+ } >+ >+ function backtrackingScope(callback) >+ { >+ let state = lexer.state; >+ let maybeError = callback(); >+ if (maybeError instanceof WSyntaxError) { >+ lexer.state = state; >+ return null; >+ } else >+ return maybeError; >+ } >+ >+ function testScope(callback) >+ { >+ let state = lexer.state; >+ let maybeError = callback(); >+ lexer.state = state; >+ return !(maybeError instanceof WSyntaxError); >+ } >+ > function genericConsume(callback, explanation) > { > let token = lexer.next(); > if (!token) >- lexer.fail("Unexpected end of file"); >+ return fail("Unexpected end of file"); > if (!callback(token)) >- lexer.fail("Unexpected token: " + token.text + "; expected: " + explanation); >+ return fail("Unexpected token: " + token.text + "; expected: " + explanation); > return token; > } >- >+ > function consume(...texts) > { > return genericConsume(token => texts.includes(token.text), texts); > } >- >+ > function consumeKind(kind) > { > return genericConsume(token => token.kind == kind, kind); > } >- >+ > function assertNext(...texts) > { >- lexer.push(consume(...texts)); >+ let maybeError = consume(...texts); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ lexer.push(maybeError); > } >- >+ > function genericTest(callback) > { > let token = lexer.peek(); >@@ -94,17 +121,17 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return token; > return null; > } >- >+ > function test(...texts) > { > return genericTest(token => texts.includes(token.text)); > } >- >+ > function testKind(kind) > { > return genericTest(token => token.kind == kind); > } >- >+ > function tryConsume(...texts) > { > let result = test(...texts); >@@ -112,7 +139,7 @@ function parse(program, origin, originKind, lineNumberOffset, text) > lexer.next(); > return result; > } >- >+ > function tryConsumeKind(kind) > { > let result = testKind(kind); >@@ -120,16 +147,19 @@ function parse(program, origin, originKind, lineNumberOffset, text) > lexer.next(); > return result; > } >- >+ > function consumeEndOfTypeArgs() > { > let rightShift = tryConsume(">>"); > if (rightShift) > lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">")); >- else >- consume(">"); >+ else { >+ let maybeError = consume(">"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ } > } >- >+ > function parseTerm() > { > let token; >@@ -140,13 +170,13 @@ function parse(program, origin, originKind, lineNumberOffset, text) > if (token = tryConsumeKind("intLiteral")) { > let intVersion = (+token.text) | 0; > if ("" + intVersion !== token.text) >- lexer.fail("Integer literal is not an integer: " + token.text); >+ return fail("Integer literal is not an integer: " + token.text); > return new IntLiteral(token, intVersion); > } > if (token = tryConsumeKind("uintLiteral")) { > let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0; > if (uintVersion + "u" !== token.text) >- lexer.fail("Integer literal is not 32-bit unsigned integer: " + token.text); >+ return fail("Integer literal is not 32-bit unsigned integer: " + token.text); > return new UintLiteral(token, uintVersion); > } > if ((token = tryConsumeKind("intHexLiteral")) >@@ -162,7 +192,7 @@ function parse(program, origin, originKind, lineNumberOffset, text) > else > intVersion = intVersion >>> 0; > if (intVersion.toString(16) !== hexString) >- lexer.fail("Hex integer literal is not an integer: " + token.text); >+ return fail("Hex integer literal is not an integer: " + token.text); > if (token.kind == "intHexLiteral") > return new IntLiteral(token, intVersion); > return new UintLiteral(token, intVersion >>> 0); >@@ -178,30 +208,48 @@ function parse(program, origin, originKind, lineNumberOffset, text) > if (token = tryConsume("true", "false")) > return new BoolLiteral(token, token.text == "true"); > // FIXME: Need support for other literals too. >- consume("("); >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result = parseExpression(); >- consume(")"); >+ if (result instanceof WSyntaxError) >+ return result; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > function parseConstexpr() > { > let token; >- if (token = tryConsume("-")) >- return new CallExpression(token, "operator" + token.text, [parseTerm()]); >+ if (token = tryConsume("-")) { >+ let term = parseTerm(); >+ if (term instanceof WSyntaxError) >+ return term; >+ return new CallExpression(token, "operator" + token.text, [term]); >+ } > let left = parseTerm(); >- if (token = tryConsume(".")) >- left = new DotExpression(token, left, consumeKind("identifier").text); >+ if (left instanceof WSyntaxError) >+ return left; >+ if (token = tryConsume(".")) { >+ let maybeError = consumeKind("identifier") >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ left = new DotExpression(token, left, maybeError.text); >+ } > return left; > } >- >+ > function parseTypeArguments() > { > if (!test("<")) > return []; > > let result = []; >- consume("<"); >+ let maybeError = consume("<"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > while (!test(">")) { > // It's possible for a constexpr or type can syntactically overlap in the single > // identifier case. Let's consider the possibilities: >@@ -214,31 +262,45 @@ function parse(program, origin, originKind, lineNumberOffset, text) > // In the future we'll allow constexprs to do more things, and then we'll still have > // the problem that something of the form T[1][2][3]... can either be a type or a > // constexpr, and we can figure out in the checker which it is. >- let typeRef = lexer.backtrackingScope(() => { >+ let typeRef = backtrackingScope(() => { > let result = consumeKind("identifier"); >- assertNext(",", ">", ">>"); >+ if (result instanceof WSyntaxError) >+ return result; >+ let maybeError = assertNext(",", ">", ">>"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new TypeRef(result, result.text); > }); > if (typeRef) > result.push(typeRef); > else { >- let constexpr = lexer.backtrackingScope(() => { >+ let constexpr = backtrackingScope(() => { > let result = parseConstexpr(); >- assertNext(",", ">", ">>"); >+ if (result instanceof WSyntaxError) >+ return result; >+ let maybeError = assertNext(",", ">", ">>"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > }); > if (constexpr) > result.push(constexpr); >- else >- result.push(parseType()); >+ else { >+ let type = parseType(); >+ if (type instanceof WSyntaxError) >+ return type; >+ result.push(type); >+ } > } > if (!tryConsume(",")) > break; > } >- consumeEndOfTypeArgs(); >+ maybeError = consumeEndOfTypeArgs(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > function parseType() > { > let token; >@@ -246,68 +308,96 @@ function parse(program, origin, originKind, lineNumberOffset, text) > let addressSpaceConsumed = false; > if (token = tryConsume(...addressSpaces)) > addressSpace = token.text; >- >+ > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let typeArguments = parseTypeArguments(); >+ if (typeArguments instanceof WSyntaxError) >+ return typeArguments; > let type = new TypeRef(name, name.text, typeArguments); >- >+ > function getAddressSpace() > { > addressSpaceConsumed = true; > if (addressSpace) > return addressSpace; >- return consume(...addressSpaces).text; >+ let consumedAddressSpace = consume(...addressSpaces); >+ if (consumedAddressSpace instanceof WSyntaxError) >+ return consumedAddressSpace; >+ return consumedAddressSpace.text; > } >- >+ > const typeConstructorStack = [ ]; > > for (let token; token = tryConsume("*", "[");) { > if (token.text == "*") { > // Likewise, the address space must be parsed before parsing continues. > const addressSpace = getAddressSpace(); >+ if (addressSpace instanceof WSyntaxError) >+ return addressSpace; > typeConstructorStack.unshift(type => new PtrType(token, addressSpace, type)); > continue; > } > > if (tryConsume("]")) { > const addressSpace = getAddressSpace(); >+ if (addressSpace instanceof WSyntaxError) >+ return addressSpace; > typeConstructorStack.unshift(type => new ArrayRefType(token, addressSpace, type)); > continue; > } > > const lengthExpr = parseConstexpr(); >+ if (lengthExpr instanceof WSyntaxError) >+ return lengthExpr; > typeConstructorStack.unshift(type => new ArrayType(token, type, lengthExpr)); >- consume("]"); >+ let maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > } > > for (let constructor of typeConstructorStack) > type = constructor(type); > > if (addressSpace && !addressSpaceConsumed) >- lexer.fail("Address space specified for type that does not need address space"); >+ return fail("Address space specified for type that does not need address space"); > > return type; > } >- >+ > function parseTypeDef() > { > let origin = consume("typedef"); >- let name = consumeKind("identifier").text; >- consume("="); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ let name = maybeError.text; >+ maybeError = consume("="); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let type = parseType(); >- consume(";"); >+ if (type instanceof WSyntaxError) >+ return type; >+ maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new TypeDef(origin, name, type); > } >- >+ > function genericParseLeft(texts, nextParser, constructor) > { > let left = nextParser(); >+ if (left instanceof WSyntaxError) >+ return left; > let token; > while (token = tryConsume(...texts)) > left = constructor(token, left, nextParser()); > return left; > } >- >+ > function parseLeftOperatorCall(texts, nextParser) > { > return genericParseLeft( >@@ -315,24 +405,32 @@ function parse(program, origin, originKind, lineNumberOffset, text) > (token, left, right) => > new CallExpression(token, "operator" + token.text, [left, right])); > } >- >+ > function parseCallExpression() > { > let parseArguments = function(origin, callName) { > let argumentList = []; > while (!test(")")) { > let argument = parsePossibleAssignment(); >+ if (argument instanceof WSyntaxError) >+ return argument; > argumentList.push(argument); > if (!tryConsume(",")) > break; > } >- consume(")"); >+ let maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new CallExpression(origin, callName, argumentList); > } > >- let name = lexer.backtrackingScope(() => { >+ let name = backtrackingScope(() => { > let name = consumeKind("identifier"); >- consume("("); >+ if (name instanceof WSyntaxError) >+ return name; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return name; > }); > >@@ -341,40 +439,52 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return result; > } else { > let returnType = parseType(); >- consume("("); >+ if (returnType instanceof WSyntaxError) >+ return returnType; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result = parseArguments(returnType.origin, "operator cast"); > result.setCastData(returnType); > return result; > } > } >- >+ > function isCallExpression() > { >- return lexer.testScope(() => { >- consumeKind("identifier"); >- consume("("); >- }) || lexer.testScope(() => { >- parseType(); >- consume("("); >+ return testScope(() => { >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ }) || testScope(() => { >+ let type = parseType(); >+ if (type instanceof WSyntaxError) >+ return type; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > }); > } >- >+ > function emitIncrement(token, old, extraArg) > { > let args = [old]; > if (extraArg) > args.push(extraArg); >- >+ > let name = "operator" + token.text; > if (/=$/.test(name)) > name = RegExp.leftContext; >- >+ > if (name == "operator") > throw new Error("Invalid name: " + name); >- >+ > return new CallExpression(token, name, args); > } >- >+ > function finishParsingPostIncrement(token, left) > { > let readModifyWrite = new ReadModifyWriteExpression(token, left); >@@ -382,7 +492,7 @@ function parse(program, origin, originKind, lineNumberOffset, text) > readModifyWrite.resultExp = readModifyWrite.oldValueRef(); > return readModifyWrite; > } >- >+ > function parseSuffixOperator(left, acceptableOperators) > { > let token; >@@ -395,11 +505,18 @@ function parse(program, origin, originKind, lineNumberOffset, text) > case "->": > if (token.text == "->") > left = new DereferenceExpression(token, left); >- left = new DotExpression(token, left, consumeKind("identifier").text); >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ left = new DotExpression(token, left, maybeError.text); > break; > case "[": { > let index = parseExpression(); >- consume("]"); >+ if (index instanceof WSyntaxError) >+ return index; >+ let maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > left = new IndexExpression(token, left, index); > break; > } >@@ -409,7 +526,7 @@ function parse(program, origin, originKind, lineNumberOffset, text) > } > return left; > } >- >+ > function parsePossibleSuffix() > { > let acceptableOperators = ["++", "--", ".", "->", "["]; >@@ -417,13 +534,18 @@ function parse(program, origin, originKind, lineNumberOffset, text) > let left; > if (isCallExpression()) { > left = parseCallExpression(); >+ if (left instanceof WSyntaxError) >+ return left; > acceptableOperators = limitedOperators; >- } else >+ } else { > left = parseTerm(); >- >+ if (left instanceof WSyntaxError) >+ return left; >+ } >+ > return parseSuffixOperator(left, acceptableOperators); > } >- >+ > function finishParsingPreIncrement(token, left, extraArg) > { > let readModifyWrite = new ReadModifyWriteExpression(token, left); >@@ -431,54 +553,72 @@ function parse(program, origin, originKind, lineNumberOffset, text) > readModifyWrite.resultExp = readModifyWrite.newValueRef(); > return readModifyWrite; > } >- >+ > function parsePreIncrement() > { > let token = consume("++", "--"); >+ if (token instanceof WSyntaxError) >+ return token; > let left = parsePossiblePrefix(); >+ if (left instanceof WSyntaxError) >+ return left; > return finishParsingPreIncrement(token, left); > } >- >+ > function parsePossiblePrefix() > { > let token; > if (test("++", "--")) > return parsePreIncrement(); >- if (token = tryConsume("+", "-", "~")) >- return new CallExpression(token, "operator" + token.text, [parsePossiblePrefix()]); >- if (token = tryConsume("*")) >- return new DereferenceExpression(token, parsePossiblePrefix()); >- if (token = tryConsume("&")) >- return new MakePtrExpression(token, parsePossiblePrefix()); >- if (token = tryConsume("@")) >- return new MakeArrayRefExpression(token, parsePossiblePrefix()); >- if (token = tryConsume("!")) { >+ if (token = tryConsume("+", "-", "~")) { >+ let possiblePrefix = parsePossiblePrefix(); >+ if (possiblePrefix instanceof WSyntaxError) >+ return WSyntaxError; >+ return new CallExpression(token, "operator" + token.text, [possiblePrefix]); >+ } if (token = tryConsume("*")) { >+ let possiblePrefix = parsePossiblePrefix(); >+ if (possiblePrefix instanceof WSyntaxError) >+ return WSyntaxError; >+ return new DereferenceExpression(token, possiblePrefix); >+ } if (token = tryConsume("&")) { >+ let possiblePrefix = parsePossiblePrefix(); >+ if (possiblePrefix instanceof WSyntaxError) >+ return WSyntaxError; >+ return new MakePtrExpression(token, possiblePrefix); >+ } if (token = tryConsume("@")) { >+ let possiblePrefix = parsePossiblePrefix(); >+ if (possiblePrefix instanceof WSyntaxError) >+ return WSyntaxError; >+ return new MakeArrayRefExpression(token, possiblePrefix); >+ } if (token = tryConsume("!")) { > let remainder = parsePossiblePrefix(); >+ if (remainder instanceof WSyntaxError) >+ return remainder; > return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [remainder])); > } > return parsePossibleSuffix(); > } >- >+ > function parsePossibleProduct() > { > return parseLeftOperatorCall(["*", "/", "%"], parsePossiblePrefix); > } >- >+ > function parsePossibleSum() > { > return parseLeftOperatorCall(["+", "-"], parsePossibleProduct); > } >- >+ > function parsePossibleShift() > { > return parseLeftOperatorCall(["<<", ">>"], parsePossibleSum); > } >- >+ > function parsePossibleRelationalInequality() > { > return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift); > } >- >+ > function parsePossibleRelationalEquality() > { > return genericParseLeft( >@@ -490,100 +630,129 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return result; > }); > } >- >+ > function parsePossibleBitwiseAnd() > { > return parseLeftOperatorCall(["&"], parsePossibleRelationalEquality); > } >- >+ > function parsePossibleBitwiseXor() > { > return parseLeftOperatorCall(["^"], parsePossibleBitwiseAnd); > } >- >+ > function parsePossibleBitwiseOr() > { > return parseLeftOperatorCall(["|"], parsePossibleBitwiseXor); > } >- >+ > function parseLeftLogicalExpression(texts, nextParser) > { > return genericParseLeft( > texts, nextParser, > (token, left, right) => new LogicalExpression(token, token.text, new CallExpression(left.origin, "bool", [left]), new CallExpression(right.origin, "bool", [right]))); > } >- >+ > function parsePossibleLogicalAnd() > { > return parseLeftLogicalExpression(["&&"], parsePossibleBitwiseOr); > } >- >+ > function parsePossibleLogicalOr() > { > return parseLeftLogicalExpression(["||"], parsePossibleLogicalAnd); > } >- >+ > function parsePossibleTernaryConditional() > { > let predicate = parsePossibleLogicalOr(); >+ if (predicate instanceof WSyntaxError) >+ return predicate; > let operator = tryConsume("?"); > if (!operator) > return predicate; > let bodyExpression = parsePossibleAssignment(); >- consume(":"); >+ if (bodyExpression instanceof WSyntaxError) >+ return bodyExpression; >+ let maybeError = consume(":"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let elseExpression = parsePossibleAssignment(); >+ if (elseExpression instanceof WSyntaxError) >+ return elseExpression; > return new TernaryExpression(operator, predicate, bodyExpression, elseExpression); > } >- >+ > function parsePossibleAssignment(mode) > { > let lhs = parsePossibleTernaryConditional(); >+ if (lhs instanceof WSyntaxError) >+ return lhs; > let operator = tryConsume("=", "+=", "-=", "*=", "/=", "%=", "^=", "|=", "&="); > if (!operator) { > if (mode == "required") >- lexer.fail("Expected assignment: " + lexer._text.substring(lexer._index)); >+ return fail("Expected assignment: " + lexer._text.substring(lexer._index)); > return lhs; > } >- if (operator.text == "=") >- return new Assignment(operator, lhs, parsePossibleAssignment()); >- return finishParsingPreIncrement(operator, lhs, parsePossibleAssignment()); >+ if (operator.text == "=") { >+ let innerAssignment = parsePossibleAssignment(); >+ if (innerAssignment instanceof WSyntaxError) >+ return innerAssignment; >+ return new Assignment(operator, lhs, innerAssignment); >+ } >+ let innerAssignment = parsePossibleAssignment(); >+ if (innerAssignment instanceof WSyntaxError) >+ return innerAssignment; >+ return finishParsingPreIncrement(operator, lhs, innerAssignment); > } >- >+ > function parseAssignment() > { > return parsePossibleAssignment("required"); > } >- >+ > function parsePostIncrement() > { >- let left = parseSuffixOperator(parseTerm(), ".", "->", "["); >+ let term = parseTerm(); >+ if (term instanceof WSyntaxError) >+ return term; >+ let left = parseSuffixOperator(term, ".", "->", "["); >+ if (left instanceof WSyntaxError) >+ return left; > let token = consume("++", "--"); >+ if (token instanceof WSyntaxError) >+ return token; > return finishParsingPostIncrement(token, left); > } >- >+ > function parseEffectfulExpression() > { > if (isCallExpression()) > return parseCallExpression(); >- let preIncrement = lexer.backtrackingScope(parsePreIncrement); >+ let preIncrement = backtrackingScope(parsePreIncrement); > if (preIncrement) > return preIncrement; >- let postIncrement = lexer.backtrackingScope(parsePostIncrement); >+ let postIncrement = backtrackingScope(parsePostIncrement); > if (postIncrement) > return postIncrement; > return parseAssignment(); > } >- >+ > function genericParseCommaExpression(finalExpressionParser) > { > let list = []; > let origin = lexer.peek(); > if (!origin) >- lexer.fail("Unexpected end of file"); >+ return fail("Unexpected end of file"); > for (;;) { >- let effectfulExpression = lexer.backtrackingScope(() => { >- parseEffectfulExpression(); >- consume(","); >+ let effectfulExpression = backtrackingScope(() => { >+ let effectfulExpression = parseEffectfulExpression(); >+ if (effectfulExpression instanceof WSyntaxError) >+ return effectfulExpression; >+ let maybeError = consume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return effectfulExpression; > }); > if (!effectfulExpression) { > let final = finalExpressionParser(); >@@ -598,89 +767,141 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return list[0]; > return new CommaExpression(origin, list); > } >- >+ > function parseCommaExpression() > { > return genericParseCommaExpression(parsePossibleAssignment); > } >- >+ > function parseExpression() > { > return parseCommaExpression(); > } >- >+ > function parseEffectfulStatement() > { > let result = genericParseCommaExpression(parseEffectfulExpression); >- consume(";"); >+ if (result instanceof WSyntaxError) >+ return result; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > function parseReturn() > { > let origin = consume("return"); >+ if (origin instanceof WSyntaxError) >+ return origin; > if (tryConsume(";")) > return new Return(origin, null); > let expression = parseExpression(); >- consume(";"); >+ if (expression instanceof WSyntaxError) >+ return expression; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new Return(origin, expression); > } >- >+ > function parseBreak() > { > let origin = consume("break"); >- consume(";"); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new Break(origin); > } >- >+ > function parseContinue() > { > let origin = consume("continue"); >- consume(";"); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new Continue(origin); > } > > function parseIfStatement() > { > let origin = consume("if"); >- consume("("); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let conditional = parseExpression(); >- consume(")"); >+ if (conditional instanceof WSyntaxError) >+ return conditional; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let body = parseStatement(); >+ if (body instanceof WSyntaxError) >+ return body; > let elseBody; >- if (tryConsume("else")) >+ if (tryConsume("else")) { > elseBody = parseStatement(); >+ if (elseBody instanceof WSyntaxError) >+ return elseBody; >+ } > return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [conditional]), body, elseBody); > } > > function parseWhile() > { > let origin = consume("while"); >- consume("("); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let conditional = parseExpression(); >- consume(")"); >+ if (conditional instanceof WSyntaxError) >+ return conditional; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let body = parseStatement(); >+ if (body instanceof WSyntaxError) >+ return body; > return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [conditional]), body); > } > > function parseFor() > { > let origin = consume("for"); >- consume("("); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let initialization; > if (tryConsume(";")) > initialization = undefined; > else { >- initialization = lexer.backtrackingScope(parseVariableDecls); >- if (!initialization) >+ initialization = backtrackingScope(parseVariableDecls); >+ if (!initialization) { > initialization = parseEffectfulStatement(); >+ if (initialization instanceof WSyntaxError) >+ return initialization; >+ } > } > let condition = tryConsume(";"); > if (condition) > condition = undefined; > else { > condition = parseExpression(); >- consume(";"); >+ if (condition instanceof WSyntaxError) >+ return condition; >+ maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > condition = new CallExpression(condition.origin, "bool", [condition]); > } > let increment; >@@ -688,59 +909,111 @@ function parse(program, origin, originKind, lineNumberOffset, text) > increment = undefined; > else { > increment = parseExpression(); >- consume(")"); >+ if (increment instanceof WSyntaxError) >+ return increment; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > } > let body = parseStatement(); >+ if (body instanceof WSyntaxError) >+ return body; > return new ForLoop(origin, initialization, condition, increment, body); > } > > function parseDo() > { > let origin = consume("do"); >+ if (origin instanceof WSyntaxError) >+ return origin; > let body = parseStatement(); >- consume("while"); >- consume("("); >+ if (body instanceof WSyntaxError) >+ return body; >+ let maybeError = consume("while"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let conditional = parseExpression(); >- consume(")"); >+ if (conditional instanceof WSyntaxError) >+ return conditional; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [conditional])); > } >- >+ > function parseVariableDecls() > { > let type = parseType(); >+ if (type instanceof WSyntaxError) >+ return type; > let list = []; > do { > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let initializer = tryConsume("=") ? parseExpression() : null; >+ if (initializer instanceof WSyntaxError) >+ return initializer; > list.push(new VariableDecl(name, name.text, type, initializer)); >- } while (consume(",", ";").text == ","); >+ let maybeError = consume(",", ";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError.text != ",") >+ break; >+ } while (true); > return new CommaExpression(type.origin, list); > } >- >+ > function parseSwitchCase() > { > let token = consume("default", "case"); >+ if (token instanceof WSyntaxError) >+ return token; > let value; >- if (token.text == "case") >+ if (token.text == "case") { > value = parseConstexpr(); >- consume(":"); >+ if (value instanceof WSyntaxError) >+ return value; >+ } >+ let maybeError = consume(":"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let body = parseBlockBody("}", "default", "case"); >+ if (body instanceof WSyntaxError) >+ return body; > return new SwitchCase(token, value, body); > } >- >+ > function parseSwitchStatement() > { > let origin = consume("switch"); >- consume("("); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let value = parseExpression(); >- consume(")"); >- consume("{"); >+ if (value instanceof WSyntaxError) >+ return value; >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ maybeError = consume("{"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result = new SwitchStatement(origin, value); >- while (!tryConsume("}")) >- result.add(parseSwitchCase()); >+ while (!tryConsume("}")) { >+ let switchCase = parseSwitchCase(); >+ if (switchCase instanceof WSyntaxError) >+ return switchCase; >+ result.add(switchCase); >+ } > return result; > } >- >+ > function parseStatement() > { > let token = lexer.peek(); >@@ -766,77 +1039,109 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return parseSwitchStatement(); > if (token.text == "trap") { > let origin = consume("trap"); >+ if (origin instanceof WSyntaxError) >+ return origin; > consume(";"); > return new TrapStatement(origin); > } > if (token.text == "{") > return parseBlock(); >- let variableDecl = lexer.backtrackingScope(parseVariableDecls); >+ let variableDecl = backtrackingScope(parseVariableDecls); > if (variableDecl) > return variableDecl; > return parseEffectfulStatement(); > } >- >+ > function parseBlockBody(...terminators) > { > let block = new Block(origin); > while (!test(...terminators)) { > let statement = parseStatement(); >+ if (statement instanceof WSyntaxError) >+ return statement; > if (statement) > block.add(statement); > } > return block; > } >- >+ > function parseBlock() > { > let origin = consume("{"); >+ if (origin instanceof WSyntaxError) >+ return origin; > let block = parseBlockBody("}"); >- consume("}"); >+ if (block instanceof WSyntaxError) >+ return block; >+ let maybeError = consume("}"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return block; > } >- >+ > function parseParameter() > { > let type = parseType(); >+ if (type instanceof WSyntaxError) >+ return type; > let name = tryConsumeKind("identifier"); > return new FuncParameter(type.origin, name ? name.text : null, type); > } >- >+ > function parseParameters() > { >- consume("("); >+ let maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let parameters = []; > while (!test(")")) { >- parameters.push(parseParameter()); >+ let parameter = parseParameter(); >+ if (parameter instanceof WSyntaxError) >+ return parameter; >+ parameters.push(parameter); > if (!tryConsume(",")) > break; > } >- consume(")"); >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return parameters; > } >- >+ > function parseFuncName() > { > if (tryConsume("operator")) { > let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", ".", "~", "<<", ">>", "["); >+ if (token instanceof WSyntaxError) >+ return token; > if (token.text == "&") { > if (tryConsume("[")) { >- consume("]"); >+ let maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return "operator&[]"; > } >- if (tryConsume(".")) >- return "operator&." + consumeKind("identifier").text; >+ if (tryConsume(".")) { >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return "operator&." + maybeError.text; >+ } > return "operator&"; > } > if (token.text == ".") { >- let result = "operator." + consumeKind("identifier").text; >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ let result = "operator." + maybeError.text; > if (tryConsume("=")) > result += "="; > return result; > } > if (token.text == "[") { >- consume("]"); >+ let maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result = "operator[]"; > if (tryConsume("=")) > result += "="; >@@ -844,7 +1149,10 @@ function parse(program, origin, originKind, lineNumberOffset, text) > } > return "operator" + token.text; > } >- return consumeKind("identifier").text; >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return maybeError.text; > } > > function parseFuncDecl() >@@ -858,127 +1166,211 @@ function parse(program, origin, originKind, lineNumberOffset, text) > if (operatorToken) { > origin = operatorToken; > returnType = parseType(); >+ if (returnType instanceof WSyntaxError) >+ return returnType; > name = "operator cast"; > isCast = true; > } else { > shaderType = tryConsume("vertex", "fragment"); > returnType = parseType(); >+ if (returnType instanceof WSyntaxError) >+ return returnType; > if (shaderType) { > origin = shaderType; > shaderType = shaderType.text; > } else > origin = returnType.origin; > name = parseFuncName(); >+ if (name instanceof WSyntaxError) >+ return name; > isCast = false; > } > let parameters = parseParameters(); >+ if (parameters instanceof WSyntaxError) >+ return parameters; > return new Func(origin, name, returnType, parameters, isCast, shaderType); > } >- >+ > function parseFuncDef() > { > let func = parseFuncDecl(); >+ if (func instanceof WSyntaxError) >+ return func; > let body = parseBlock(); >+ if (body instanceof WSyntaxError) >+ return body; > return new FuncDef(func.origin, func.name, func.returnType, func.parameters, body, func.isCast, func.shaderType); > } >- >+ > function parseField() > { > let type = parseType(); >+ if (type instanceof WSyntaxError) >+ return type; > let name = consumeKind("identifier"); >- consume(";"); >+ if (name instanceof WSyntaxError) >+ return name; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new Field(name, name.text, type); > } >- >+ > function parseStructType() > { > let origin = consume("struct"); >- let name = consumeKind("identifier").text; >- let result = new StructType(origin, name); >- consume("{"); >- while (!tryConsume("}")) >- result.add(parseField()); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; >+ let result = new StructType(origin, name.text); >+ let maybeError = consume("{"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ while (!tryConsume("}")) { >+ let field = parseField(); >+ if (field instanceof WSyntaxError) >+ return field; >+ result.add(field); >+ } > return result; > } >- >+ > function parseNativeFunc() > { > let func = parseFuncDecl(); >- consume(";"); >+ if (func instanceof WSyntaxError) >+ return func; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new NativeFunc(func.origin, func.name, func.returnType, func.parameters, func.isCast, func.shaderType); > } >- >+ > function parseNative() > { > let origin = consume("native"); >+ if (origin instanceof WSyntaxError) >+ return origin; > if (tryConsume("typedef")) { > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let args = parseTypeArguments(); >- consume(";"); >+ if (args instanceof WSyntaxError) >+ return args; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return NativeType.create(origin, name.text, args); > } > return parseNativeFunc(); > } >- >+ > function parseRestrictedFuncDef() > { >- consume("restricted"); >+ let maybeError = consume("restricted"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result; >- if (tryConsume("native")) >+ if (tryConsume("native")) { > result = parseNativeFunc(); >- else >+ if (result instanceof WSyntaxError) >+ return result; >+ } else { > result = parseFuncDef(); >+ if (result instanceof WSyntaxError) >+ return result; >+ } > result.isRestricted = true; > return result; > } >- >+ > function parseEnumMember() > { > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let value = null; >- if (tryConsume("=")) >+ if (tryConsume("=")) { > value = parseConstexpr(); >+ if (value instanceof WSyntaxError) >+ return value; >+ } > return new EnumMember(name, name.text, value); > } >- >+ > function parseEnumType() > { >- consume("enum"); >+ let maybeError = consume("enum"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let baseType; >- if (tryConsume(":")) >+ if (tryConsume(":")) { > baseType = parseType(); >- else >+ if (baseType instanceof WSyntaxError) >+ return baseType; >+ } else > baseType = new TypeRef(name, "int"); >- consume("{"); >+ maybeError = consume("{"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > let result = new EnumType(name, name.text, baseType); > while (!test("}")) { >- result.add(parseEnumMember()); >+ let enumMember = parseEnumMember(); >+ if (enumMember instanceof WSyntaxError) >+ return enumMember; >+ result.add(enumMember); > if (!tryConsume(",")) > break; > } >- consume("}"); >+ maybeError = consume("}"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > for (;;) { > let token = lexer.peek(); > if (!token) > return; > if (token.text == ";") > lexer.next(); >- else if (token.text == "typedef") >- program.add(parseTypeDef()); >- else if (originKind == "native" && token.text == "native") >- program.add(parseNative()); >- else if (originKind == "native" && token.text == "restricted") >- program.add(parseRestrictedFuncDef()); >- else if (token.text == "struct") >- program.add(parseStructType()); >- else if (token.text == "enum") >- program.add(parseEnumType()); >- else >- program.add(parseFuncDef()); >+ else if (token.text == "typedef") { >+ let typeDef = parseTypeDef(); >+ if (typeDef instanceof WSyntaxError) >+ throw typeDef; >+ program.add(typeDef); >+ } else if (originKind == "native" && token.text == "native") { >+ let native = parseNative(); >+ if (native instanceof WSyntaxError) >+ throw native; >+ program.add(native); >+ } else if (originKind == "native" && token.text == "restricted") { >+ let restrictedFuncDef = parseRestrictedFuncDef(); >+ if (restrictedFuncDef instanceof WSyntaxError) >+ throw restrictedFuncDef; >+ program.add(restrictedFuncDef); >+ } else if (token.text == "struct") { >+ let struct = parseStructType(); >+ if (struct instanceof WSyntaxError) >+ throw struct; >+ program.add(struct); >+ } else if (token.text == "enum") { >+ let enumType = parseEnumType(); >+ if (enumType instanceof WSyntaxError) >+ throw enumType; >+ program.add(enumType); >+ } else { >+ let funcDef = parseFuncDef(); >+ if (funcDef instanceof WSyntaxError) >+ throw funcDef; >+ program.add(funcDef); >+ } > } > } > >diff --git a/Tools/WebGPUShadingLanguageRI/SPIRV.html b/Tools/WebGPUShadingLanguageRI/SPIRV.html >index 1b26cf2b2e651527a152ee8d92ff25beda61d339..804cd9abda6d5c3bec03be2582aa3f23f007a188 100644 >--- a/Tools/WebGPUShadingLanguageRI/SPIRV.html >+++ b/Tools/WebGPUShadingLanguageRI/SPIRV.html >@@ -151,6 +151,7 @@ td { > <script src="VariableRef.js"></script> > <script src="VectorType.js"></script> > <script src="VisitingSet.js"></script> >+ <script src="WLexicalError.js"></script> > <script src="WSyntaxError.js"></script> > <script src="WTrapError.js"></script> > <script src="WTypeError.js"></script> >diff --git a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >index fb175e26a27a46548ec9c2a563d38032ff1e49c4..cf3093bbe8cf37b293d38a79e6e769116c449338 100644 >--- a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >+++ b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >@@ -773,8 +773,7 @@ let standardLibrary = (function() { > } > return result; > } >- >- /* >+ > for (let type of [`bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) { > for (let size of [2, 3, 4]) { > for (let maxValue of [2, 3, 4]) { >@@ -1889,7 +1888,7 @@ let standardLibrary = (function() { > } > } > print(); >- >+ /* > for (let type of [`uint`, `int`]) { > for (let functionName of [`Add`, `And`, `Exchange`, `Max`, `Min`, `Or`, `Xor`]) { > print(`native void Interlocked${functionName}(thread atomic_${type}*, ${type}, thread ${type}*);`); >@@ -1898,7 +1897,6 @@ let standardLibrary = (function() { > } > print(); > */ >- > for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) { > for (let length of [``, `2`, `3`, `4`]) { > print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location);`); >diff --git a/Tools/WebGPUShadingLanguageRI/Test.html b/Tools/WebGPUShadingLanguageRI/Test.html >index fb1015f19381cf6eac7317b485ef00c3ec1cb96e..f5ea3d90198dcdb87131f92c250c743304b66ac0 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.html >+++ b/Tools/WebGPUShadingLanguageRI/Test.html >@@ -145,6 +145,7 @@ > <script src="VariableRef.js"></script> > <script src="VectorType.js"></script> > <script src="VisitingSet.js"></script> >+<script src="WLexicalError.js"></script> > <script src="WSyntaxError.js"></script> > <script src="WTrapError.js"></script> > <script src="WTypeError.js"></script> >diff --git a/Tools/WebGPUShadingLanguageRI/Test.js b/Tools/WebGPUShadingLanguageRI/Test.js >index 90d5e5ccd50cff4a942b91766b272869f0944c67..556cb2fb8bb5108790c5b4da8fa67e4c54cac666 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.js >+++ b/Tools/WebGPUShadingLanguageRI/Test.js >@@ -329,23 +329,6 @@ tests = new Proxy({}, { > } > }); > >-tests.commentParsing = function() { >- let program = doPrep(` >- /* this comment >- runs over multiple lines */ >- bool foo() { return true; } >- `); >- checkBool(program, callFunction(program, "foo", []), true); >- >- checkFail( >- () => doPrep(` >- /* this comment >- runs over multiple lines >- bool foo() { return true; } >- `), >- (e) => e instanceof WSyntaxError); >-} >- > tests.ternaryExpression = function() { > let program = doPrep(` > int foo(int x) >@@ -7626,6 +7609,23 @@ tests.textureGather = function() { > // FIXME: Gather other components > } > >+tests.commentParsing = function() { >+ let program = doPrep(` >+ /* this comment >+ runs over multiple lines */ >+ bool foo() { return true; } >+ `); >+ checkBool(program, callFunction(program, "foo", []), true); >+ >+ checkFail( >+ () => doPrep(` >+ /* this comment >+ runs over multiple lines >+ bool foo() { return true; } >+ `), >+ (e) => e instanceof WLexicalError); >+} >+ > okToTest = true; > > let testFilter = /.*/; // run everything by default >@@ -7683,4 +7683,3 @@ if (!this.window) { > for (let _ of doTest(testFilter)) { } > } > >- >diff --git a/Tools/WebGPUShadingLanguageRI/WLexicalError.js b/Tools/WebGPUShadingLanguageRI/WLexicalError.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c985893d29f6becdc5939cb1a2e5366e48ae15f9 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/WLexicalError.js >@@ -0,0 +1,35 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+"use strict"; >+ >+class WLexicalError extends Error { >+ constructor(originString, message) >+ { >+ super("Lexical error at " + originString + ": " + message); >+ this.originString = originString; >+ this.syntaxErrorMessage = message; >+ } >+} >+ >diff --git a/Tools/WebGPUShadingLanguageRI/WSyntaxError.js b/Tools/WebGPUShadingLanguageRI/WSyntaxError.js >index 625d8c9cad452c35931cfa524a63d1e63d71d5ba..781b0ee9a7ae9af2d8fb54dcb429e80b07ede729 100644 >--- a/Tools/WebGPUShadingLanguageRI/WSyntaxError.js >+++ b/Tools/WebGPUShadingLanguageRI/WSyntaxError.js >@@ -24,10 +24,10 @@ > */ > "use strict"; > >-class WSyntaxError extends Error { >+class WSyntaxError { > constructor(originString, message) > { >- super("Syntax error at " + originString + ": " + message); >+ this.payload = "Syntax error at " + originString + ": " + message; > this.originString = originString; > this.syntaxErrorMessage = message; > } >diff --git a/Tools/WebGPUShadingLanguageRI/index.html b/Tools/WebGPUShadingLanguageRI/index.html >index e6e13dfe8dfa5c5332ad9ef049ecea359b7e3a42..dfc90c4c2394395458865c4a8d65486870c26234 100644 >--- a/Tools/WebGPUShadingLanguageRI/index.html >+++ b/Tools/WebGPUShadingLanguageRI/index.html >@@ -145,6 +145,7 @@ > <script src="VariableRef.js"></script> > <script src="VectorType.js"></script> > <script src="VisitingSet.js"></script> >+<script src="WLexicalError.js"></script> > <script src="WSyntaxError.js"></script> > <script src="WTrapError.js"></script> > <script src="WTypeError.js"></script>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 189014
:
348887
|
348951
|
348955
|
348970
|
348985
|
348993
| 348994