WebKit Bugzilla
Attachment 348951 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]
first draft
bug-189014-20180905114254.patch (text/plain), 60.82 KB, created by
Myles C. Maxfield
on 2018-09-05 11:42:55 PDT
(
hide
)
Description:
first draft
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2018-09-05 11:42:55 PDT
Size:
60.82 KB
patch
obsolete
>Subversion Revision: 235674 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index ce6e452cb182c69d0d575f541c2abcc4382739cd..7a469d6a2ad8a1fe76eb46b573fb077ece8db8a1 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,51 @@ >+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!). >+ >+ * WebGPUShadingLanguageRI/Lexer.js: >+ (Lexer.prototype.next): >+ (Lexer): >+ * WebGPUShadingLanguageRI/Parse.js: >+ (genericConsume): >+ (genericTest): >+ (consumeEndOfTypeArgs): >+ (parseTerm): >+ (parseTypeArguments): >+ (parseType): >+ (parseTypeDef): >+ (parseCallExpression.let.parseArguments): >+ (isCallExpression): >+ (parseSuffixOperator): >+ (parsePreIncrement): >+ (parsePossibleTernaryConditional): >+ (parsePossibleAssignment): >+ (parsePostIncrement): >+ (genericParseCommaExpression): >+ (parseEffectfulStatement): >+ (parseReturn): >+ (parseBreak): >+ (parseContinue): >+ (parseIfStatement): >+ (parseWhile): >+ (parseFor): >+ (parseDo): >+ (parseVariableDecls): >+ (parseSwitchCase): >+ (parseSwitchStatement): >+ (parseStatement): >+ (parseBlock): >+ (parseFuncName): >+ (parseField): >+ (parseStructType): >+ (parseNativeFunc): >+ (parseNative): >+ (parseRestrictedFuncDef): >+ (parseEnumType): >+ (parse): >+ > 2018-09-05 David Kilzer <ddkilzer@apple.com> > > REGRESSION (r209470): EditingHistory folder is missing in EditingHistory Xcode project >diff --git a/Tools/WebGPUShadingLanguageRI/Lexer.js b/Tools/WebGPUShadingLanguageRI/Lexer.js >index 956dca336a2a9a3121a277285ae3db76dde72370..f800c118eacd8b30390aa515ab5d43be4e5e649c 100644 >--- a/Tools/WebGPUShadingLanguageRI/Lexer.js >+++ b/Tools/WebGPUShadingLanguageRI/Lexer.js >@@ -73,7 +73,7 @@ class Lexer { > { > return Lexer._textIsIdentifierImpl(text) && !RegExp.rightContext.length; > } >- >+ > next() > { > if (this._stack.length) >@@ -102,7 +102,7 @@ class Lexer { > if (/^\/\*/.test(relevantText)) { > let endIndex = relevantText.search(/\*\//); > if (endIndex < 0) >- this.fail("Unterminated comment"); >+ return this.fail("Unterminated comment"); > this._index += endIndex + 2; > continue; > } >@@ -149,52 +149,44 @@ class Lexer { > let remaining = relevantText.substring(0, 20).split(/\s/)[0]; > if (!remaining.length) > remaining = relevantText.substring(0, 20); >- this.fail("Unrecognized token beginning with: " + remaining); >+ return this.fail("Unrecognized token beginning with: " + remaining); > } > > push(token) > { > this._stack.push(token); > } >- >+ > peek() > { > let result = this.next(); >+ if (result instanceof WSyntaxError) >+ return result; > this.push(result); > return result; > } > > fail(error) > { >- throw new WSyntaxError(this.originString, error); >+ return 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; >+ let result = callback(); >+ if (result instanceof WSyntaxError) { >+ this.state = state; >+ return null; > } >+ return result; > } > > testScope(callback) > { > let state = this.state; >- try { >- callback(); >- return true; >- } catch (e) { >- if (e instanceof WSyntaxError) >- return false; >- throw e; >- } finally { >- this.state = state; >- } >+ let result = callback(); >+ this.state = state; >+ return !(result instanceof WSyntaxError); > } > } >diff --git a/Tools/WebGPUShadingLanguageRI/Parse.js b/Tools/WebGPUShadingLanguageRI/Parse.js >index ee4c980f3a1672b68a77ebb48525edd249443a53..02f661645a7d18a5568c9217761393296e9ffa47 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,58 +61,75 @@ 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 genericConsume(callback, explanation) > { > let token = lexer.next(); > if (!token) >- lexer.fail("Unexpected end of file"); >+ return lexer.fail("Unexpected end of file"); >+ if (token instanceof WSyntaxError) >+ return token; > if (!callback(token)) >- lexer.fail("Unexpected token: " + token.text + "; expected: " + explanation); >+ return lexer.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 result = consume(...texts); >+ if (result instanceof WSyntaxError) >+ return result; >+ lexer.push(result); > } >- >+ >+ // This can still return an error for things like unterminated comments. > function genericTest(callback) > { > let token = lexer.peek(); >- if (token && callback(token)) >+ if (!token) >+ return null; >+ if (token instanceof WSyntaxError) >+ return token; >+ if (callback(token)) > return token; > return null; > } >- >+ >+ // This can still return an error for things like unterminated comments. > function test(...texts) > { > return genericTest(token => texts.includes(token.text)); > } >- >+ >+ // This can still return an error for things like unterminated comments. > function testKind(kind) > { > return genericTest(token => token.kind == kind); > } >- >+ >+ // This can still return an error for things like unterminated comments. > function tryConsume(...texts) > { > let result = test(...texts); >- if (result) >- lexer.next(); >+ if (!result) >+ return result; >+ if (result instanceof WSyntaxError) >+ return result; >+ lexer.next(); > return result; > } >- >+ >+ // This can still return an error for things like unterminated comments. > function tryConsumeKind(kind) > { > let result = testKind(kind); >@@ -120,37 +137,56 @@ function parse(program, origin, originKind, lineNumberOffset, text) > lexer.next(); > return result; > } >- >+ > function consumeEndOfTypeArgs() > { > let rightShift = tryConsume(">>"); >+ if (rightShift instanceof WSyntaxError) >+ return rightShift; > if (rightShift) > lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">")); >- else >- consume(">"); >+ else { >+ let result = consume(">"); >+ if (result instanceof WSyntaxError) >+ return result; >+ } > } >- >+ > function parseTerm() > { > let token; >- if (token = tryConsume("null")) >+ if (token = tryConsume("null")) { >+ if (token instanceof WSyntaxError) >+ return token; > return new NullLiteral(token); >- if (token = tryConsumeKind("identifier")) >+ } >+ if (token = tryConsumeKind("identifier")) { >+ if (token instanceof WSyntaxError) >+ return token; > return new VariableRef(token, token.text); >+ } > if (token = tryConsumeKind("intLiteral")) { >+ if (token instanceof WSyntaxError) >+ return token; > let intVersion = (+token.text) | 0; > if ("" + intVersion !== token.text) >- lexer.fail("Integer literal is not an integer: " + token.text); >+ return lexer.fail("Integer literal is not an integer: " + token.text); > return new IntLiteral(token, intVersion); > } > if (token = tryConsumeKind("uintLiteral")) { >+ if (token instanceof WSyntaxError) >+ return token; > 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 lexer.fail("Integer literal is not 32-bit unsigned integer: " + token.text); > return new UintLiteral(token, uintVersion); > } >- if ((token = tryConsumeKind("intHexLiteral")) >- || (token = tryConsumeKind("uintHexLiteral"))) { >+ token = tryConsumeKind("intHexLiteral"); >+ if (token instanceof WSyntaxError) >+ return token; >+ if (token || (token = tryConsumeKind("uintHexLiteral"))) { >+ if (token instanceof WSyntaxError) >+ return token; > let hexString = token.text.substr(2); > if (token.kind == "uintHexLiteral") > hexString = hexString.substr(0, hexString.length - 1); >@@ -162,12 +198,14 @@ 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 lexer.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); > } > if (token = tryConsumeKind("floatLiteral")) { >+ if (token instanceof WSyntaxError) >+ return token; > let text = token.text; > let f = token.text.endsWith("f"); > if (f) >@@ -175,33 +213,58 @@ function parse(program, origin, originKind, lineNumberOffset, text) > let value = parseFloat(text); > return new FloatLiteral(token, Math.fround(value)); > } >- if (token = tryConsume("true", "false")) >+ if (token = tryConsume("true", "false")) { >+ if (token instanceof WSyntaxError) >+ return token; > return new BoolLiteral(token, token.text == "true"); >+ } > // FIXME: Need support for other literals too. >- consume("("); >+ let parenthesisResult = consume("("); >+ if (parenthesisResult instanceof WSyntaxError) >+ return parenthesisResult; > let result = parseExpression(); >- consume(")"); >+ if (result instanceof WSyntaxError) >+ return result; >+ parenthesisResult = consume(")"); >+ if (parenthesisResult instanceof WSyntaxError) >+ return parenthesisResult; > return result; > } >- >+ > function parseConstexpr() > { > let token; >- if (token = tryConsume("-")) >- return new CallExpression(token, "operator" + token.text, [parseTerm()]); >+ if (token = tryConsume("-")) { >+ if (token instanceof WSyntaxError) >+ return token; >+ let maybeError = parseTerm(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new CallExpression(token, "operator" + token.text, [maybeError]); >+ } > let left = parseTerm(); >- if (token = tryConsume(".")) >- left = new DotExpression(token, left, consumeKind("identifier").text); >+ if (left instanceof WSyntaxError) >+ return left; >+ if (token = tryConsume(".")) { >+ if (token instanceof WSyntaxError) >+ return token; >+ 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 bracketResult = consume("<"); >+ if (bracketResult instanceof WSyntaxError) >+ return bracketResult; > while (!test(">")) { > // It's possible for a constexpr or type can syntactically overlap in the single > // identifier case. Let's consider the possibilities: >@@ -216,7 +279,11 @@ function parse(program, origin, originKind, lineNumberOffset, text) > // constexpr, and we can figure out in the checker which it is. > let typeRef = lexer.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) >@@ -224,90 +291,144 @@ function parse(program, origin, originKind, lineNumberOffset, text) > else { > let constexpr = lexer.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 maybeError = parseType(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ result.push(maybeError); >+ } > } >- if (!tryConsume(",")) >+ let maybeError = tryConsume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (!maybeError) > break; > } >- consumeEndOfTypeArgs(); >+ let maybeError = consumeEndOfTypeArgs(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > function parseType() > { > let token; > let addressSpace; > let addressSpaceConsumed = false; >- if (token = tryConsume(...addressSpaces)) >+ if (token = tryConsume(...addressSpaces)) { >+ if (token instanceof WSyntaxError) >+ return token; > 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 maybeError = consume(...addressSpaces); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return maybeError.text; > } >- >+ > const typeConstructorStack = [ ]; > > for (let token; token = tryConsume("*", "[");) { >+ if (token instanceof WSyntaxError) >+ return token; > 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("]")) { >+ let maybeError = tryConsume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > 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 bracketResult = consume("]"); >+ if (bracketResult instanceof WSyntaxError) >+ return bracketResult; > } > > 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 lexer.fail("Address space specified for type that does not need address space"); > > return type; > } >- >+ > function parseTypeDef() > { > let origin = consume("typedef"); >+ if (origin instanceof WSyntaxError) >+ return origin > let name = consumeKind("identifier").text; >- consume("="); >+ if (name instanceof WSyntaxError) >+ return name; >+ let 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()); >+ while (token = tryConsume(...texts)) { >+ if (token instanceof WSyntaxError) >+ return token; >+ let maybeError = nextParser(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ left = constructor(token, left, maybeError); >+ } > return left; > } >- >+ > function parseLeftOperatorCall(texts, nextParser) > { > return genericParseLeft( >@@ -315,24 +436,35 @@ 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(",")) >+ let maybeError = tryConsume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (!maybeError) > break; > } >- consume(")"); >+ let maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new CallExpression(origin, callName, argumentList); > } > > let name = lexer.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 +473,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("("); >+ let maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ maybeError = consume("("); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > }) || lexer.testScope(() => { >- parseType(); >- consume("("); >+ let maybeError = parseType(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ 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,11 +526,13 @@ function parse(program, origin, originKind, lineNumberOffset, text) > readModifyWrite.resultExp = readModifyWrite.oldValueRef(); > return readModifyWrite; > } >- >+ > function parseSuffixOperator(left, acceptableOperators) > { > let token; > while (token = tryConsume(...acceptableOperators)) { >+ if (token instanceof WSyntaxError) >+ return token; > switch (token.text) { > case "++": > case "--": >@@ -395,11 +541,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,21 +562,29 @@ function parse(program, origin, originKind, lineNumberOffset, text) > } > return left; > } >- >+ > function parsePossibleSuffix() > { > let acceptableOperators = ["++", "--", ".", "->", "["]; > let limitedOperators = [".", "->", "["]; > let left; >- if (isCallExpression()) { >+ let maybeError = isCallExpression(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > 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 +592,86 @@ 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 instanceof WSyntaxError) >+ return token; >+ let maybeError = parsePossiblePrefix(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new CallExpression(token, "operator" + token.text, [maybeError]); >+ } >+ if (token = tryConsume("*")) { >+ if (token instanceof WSyntaxError) >+ return token; >+ let maybeError = parsePossiblePrefix(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new DereferenceExpression(token, maybeError); >+ } >+ if (token = tryConsume("&")) { >+ if (token instanceof WSyntaxError) >+ return token; >+ let maybeError = parsePossiblePrefix(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new MakePtrExpression(token, maybeError); >+ } >+ if (token = tryConsume("@")) { >+ if (token instanceof WSyntaxError) >+ return token; >+ let maybeError = parsePossiblePrefix(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new MakeArrayRefExpression(token, maybeError); >+ } > if (token = tryConsume("!")) { >+ if (token instanceof WSyntaxError) >+ return token; > 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,81 +683,114 @@ 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(); > let operator = tryConsume("?"); >+ if (operator instanceof WSyntaxError) >+ return operator; > 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 instanceof WSyntaxError) >+ return operator; > if (!operator) { > if (mode == "required") >- lexer.fail("Expected assignment: " + lexer._text.substring(lexer._index)); >+ return lexer.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 maybeError = parsePossibleAssignment(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return new Assignment(operator, lhs, maybeError); >+ } >+ let maybeError = parsePossibleAssignment(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return finishParsingPreIncrement(operator, lhs, maybeError); > } >- >+ > function parseAssignment() > { > return parsePossibleAssignment("required"); > } >- >+ > function parsePostIncrement() > { >- let left = parseSuffixOperator(parseTerm(), ".", "->", "["); >+ let maybeError = parseTerm(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ let left = parseSuffixOperator(maybeError, ".", "->", "["); >+ 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 maybeError = isCallExpression(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { >+ maybeError = parseCallExpression(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return maybeError; >+ } > let preIncrement = lexer.backtrackingScope(parsePreIncrement); > if (preIncrement) > return preIncrement; >@@ -573,20 +799,29 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return postIncrement; > return parseAssignment(); > } >- >+ > function genericParseCommaExpression(finalExpressionParser) > { > let list = []; > let origin = lexer.peek(); > if (!origin) >- lexer.fail("Unexpected end of file"); >+ return lexer.fail("Unexpected end of file"); >+ if (origin instanceof WSyntaxError) >+ return origin; > for (;;) { > let effectfulExpression = lexer.backtrackingScope(() => { >- parseEffectfulExpression(); >- consume(","); >+ let maybeError = parseEffectfulExpression(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ // FIXME: This seems wrong. We don't return the effectful expression we just parsed. >+ maybeError = consume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > }); > if (!effectfulExpression) { > let final = finalExpressionParser(); >+ if (final instanceof WSyntaxError) >+ return final; > list.push(final); > break; > } >@@ -598,152 +833,280 @@ 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(";"); >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > function parseReturn() > { > let origin = consume("return"); >- if (tryConsume(";")) >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = tryConsume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) > return new Return(origin, null); > let expression = parseExpression(); >- consume(";"); >+ if (expression instanceof WSyntaxError) >+ return expression; >+ 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")) >+ maybeError = tryConsume("else"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > 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(";")) >+ maybeError = tryConsume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) > initialization = undefined; > else { > initialization = lexer.backtrackingScope(parseVariableDecls); >- if (!initialization) >+ if (initialization instanceof WSyntaxError) >+ return initialization; >+ if (!initialization) { > initialization = parseEffectfulStatement(); >+ if (initialization instanceof WSyntaxError) >+ return initialization; >+ } > } > let condition = tryConsume(";"); >+ if (condition instanceof WSyntaxError) >+ return condition; > 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; >- if (tryConsume(")")) >+ maybeError = tryConsume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) > 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 = []; >+ let repeat; > do { > let name = consumeKind("identifier"); >- let initializer = tryConsume("=") ? parseExpression() : null; >+ if (name instanceof WSyntaxError) >+ return name; >+ let maybeError = tryConsume("="); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ let initializer = maybeError ? parseExpression() : null; >+ if (initializer instanceof WSyntaxError) >+ return initializer; > list.push(new VariableDecl(name, name.text, type, initializer)); >- } while (consume(",", ";").text == ","); >+ maybeError = consume(",", ";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ repeat = maybeError.text == ","; >+ } while (repeat); > 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 WSyntaxError; >+ } >+ 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 (true) { >+ maybeError = tryConsume("}"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) >+ break; >+ maybeError = parseSwitchCase(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ result.add(maybeError); >+ } > return result; > } >- >+ > function parseStatement() > { > let token = lexer.peek(); >+ if (token instanceof WSyntaxError) >+ return token; > if (token.text == ";") { > lexer.next(); > return null; >@@ -766,85 +1129,144 @@ function parse(program, origin, originKind, lineNumberOffset, text) > return parseSwitchStatement(); > if (token.text == "trap") { > let origin = consume("trap"); >- consume(";"); >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = consume(";"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return new TrapStatement(origin); > } > if (token.text == "{") > return parseBlock(); > let variableDecl = lexer.backtrackingScope(parseVariableDecls); >+ if (variableDecl instanceof WSyntaxError) >+ return variableDecl; > 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"); >+ if (name instanceof WSyntaxError) >+ return name; > 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()); >- if (!tryConsume(",")) >+ maybeError = parseParameter(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ parameters.push(maybeError); >+ maybeError = tryConsume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (!maybeError) > break; > } >- consume(")"); >+ maybeError = consume(")"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return parameters; > } >- >+ > function parseFuncName() > { >- if (tryConsume("operator")) { >+ let maybeError = tryConsume("operator"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", ".", "~", "<<", ">>", "["); >+ if (token instanceof WSyntaxError) >+ return token; > if (token.text == "&") { >- if (tryConsume("[")) { >- consume("]"); >+ maybeError = tryConsume("["); >+ if (maybeError instanceof WSyntaxError); >+ return maybeError; >+ if (maybeError) { >+ maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return "operator&[]"; > } >- if (tryConsume(".")) >- return "operator&." + consumeKind("identifier").text; >+ maybeError = tryConsume("."); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { >+ maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return "operator&." + maybeError.text; >+ } > return "operator&"; > } > if (token.text == ".") { >- let result = "operator." + consumeKind("identifier").text; >- if (tryConsume("=")) >+ maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ let result = "operator." + maybeError.text; >+ maybeError = tryConsume("="); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) > result += "="; > return result; > } > if (token.text == "[") { >- consume("]"); >+ maybeError = consume("]"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError > let result = "operator[]"; >- if (tryConsume("=")) >+ maybeError = tryConsume("="); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) > result += "="; > return result; > } > return "operator" + token.text; > } >- return consumeKind("identifier").text; >+ maybeError = consumeKind("identifier"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ return maybeError.text; > } > > function parseFuncDecl() >@@ -855,130 +1277,241 @@ function parse(program, origin, originKind, lineNumberOffset, text) > let isCast; > let shaderType; > let operatorToken = tryConsume("operator"); >+ if (operatorToken instanceof WSyntaxError) >+ return operatorToken; > if (operatorToken) { > origin = operatorToken; > returnType = parseType(); >+ if (returnType instanceof WSyntaxError) >+ return returnType; > name = "operator cast"; > isCast = true; > } else { > shaderType = tryConsume("vertex", "fragment"); >+ if (shaderType instanceof WSyntaxError) >+ return shaderType; > 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"); >+ if (origin instanceof WSyntaxError) >+ return origin; > let name = consumeKind("identifier").text; >+ if (name instanceof WSyntaxError) >+ return name; > let result = new StructType(origin, name); >- consume("{"); >- while (!tryConsume("}")) >- result.add(parseField()); >+ let maybeError = consume("{"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ while (true) { >+ maybeError = tryConsume("}"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) >+ break; >+ maybeError = parseField(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ result.add(maybeError); >+ } > 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 (tryConsume("typedef")) { >+ if (origin instanceof WSyntaxError) >+ return origin; >+ let maybeError = tryConsume("typedef"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > let name = consumeKind("identifier"); >+ if (name instanceof WSyntaxError) >+ return name; > let args = parseTypeArguments(); >- consume(";"); >+ if (args instanceof WSyntaxError) >+ return args; >+ 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")) >+ maybeError = tryConsume("native"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > 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("=")) >+ let maybeError = tryConsume("="); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > 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(":")) >+ maybeError = tryConsume(":"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (maybeError) { > baseType = parseType(); >+ 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()); >- if (!tryConsume(",")) >+ maybeError = parseEnumMember(); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ result.add(maybeError); >+ maybeError = tryConsume(","); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; >+ if (!maybeError) > break; > } >- consume("}"); >+ maybeError = consume("}"); >+ if (maybeError instanceof WSyntaxError) >+ return maybeError; > return result; > } >- >+ > for (;;) { > let token = lexer.peek(); >+ if (token instanceof WSyntaxError) >+ throw token; > 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 maybeError = parseTypeDef(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } else if (originKind == "native" && token.text == "native") { >+ let maybeError = parseNative(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } else if (originKind == "native" && token.text == "restricted") { >+ let maybeError = parseRestrictedFuncDef(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } else if (token.text == "struct") { >+ let maybeError = parseStructType(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } else if (token.text == "enum") { >+ let maybeError = parseEnumType(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } else { >+ let maybeError = parseFuncDef(); >+ if (maybeError instanceof WSyntaxError) >+ throw maybeError; >+ program.add(maybeError); >+ } > } > } >
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