WebKit Bugzilla
Attachment 358902 Details for
Bug 192355
: [WHLSL] Add a handwritten parser
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192355-20190111093536.patch (text/plain), 120.88 KB, created by
Myles C. Maxfield
on 2019-01-11 09:35:37 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2019-01-11 09:35:37 PST
Size:
120.88 KB
patch
obsolete
>Subversion Revision: 239863 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index da837e764364a8367dd180a8a456daa05946636a..bd6473d2a367441989718e211fb47dcdf5f310d5 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,102 @@ >+2019-01-11 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Add a handwritten parser >+ https://bugs.webkit.org/show_bug.cgi?id=192355 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The parser is a mechanical representation of WHLSL's ANTLR grammar at >+ https://github.com/gpuweb/WHLSL/blob/master/Spec/WHLSL.g4. The parser >+ uses Expected<> to return an appropriate Error string when parsing fails. >+ >+ This patch doesn't include the AST nodes themselves - those are in >+ https://bugs.webkit.org/show_bug.cgi?id=192991. I split up the patch to >+ aid easier reviewing. >+ >+ No new tests because the parser isn't hooked up yet. >+ >+ * Modules/webgpu/WHLSL/WHLSLParser.cpp: >+ (WebCore::WHLSL::Parser::Parser): >+ (WebCore::WHLSL::Parser::parse): >+ (WebCore::WHLSL::Parser::fail): >+ (WebCore::WHLSL::Parser::peek): >+ (WebCore::WHLSL::Parser::tryType): >+ (WebCore::WHLSL::Parser::tryTypes): >+ (WebCore::WHLSL::Parser::consumeType): >+ (WebCore::WHLSL::Parser::consumeTypes): >+ (WebCore::WHLSL::digitValue): >+ (WebCore::WHLSL::intLiteralToInt): >+ (WebCore::WHLSL::uintLiteralToUint): >+ (WebCore::WHLSL::floatLiteralToFloat): >+ (WebCore::WHLSL::Parser::consumeIntegralLiteral): >+ (WebCore::WHLSL::Parser::consumeNonNegativeIntegralLiteral): >+ (WebCore::WHLSL::recognizeSimpleUnsignedInteger): >+ (WebCore::WHLSL::Parser::parseConstantExpression): >+ (WebCore::WHLSL::Parser::parseTypeArgument): >+ (WebCore::WHLSL::Parser::parseTypeArguments): >+ (WebCore::WHLSL::Parser::parseTypeSuffixAbbreviated): >+ (WebCore::WHLSL::Parser::parseTypeSuffixNonAbbreviated): >+ (WebCore::WHLSL::Parser::parseAddressSpaceType): >+ (WebCore::WHLSL::Parser::parseNonAddressSpaceType): >+ (WebCore::WHLSL::Parser::parseType): >+ (WebCore::WHLSL::Parser::parseTypeDefinition): >+ (WebCore::WHLSL::Parser::parseBuiltInSemantic): >+ (WebCore::WHLSL::Parser::parseResourceSemantic): >+ (WebCore::WHLSL::Parser::parseSpecializationConstantSemantic): >+ (WebCore::WHLSL::Parser::parseStageInOutSemantic): >+ (WebCore::WHLSL::Parser::parseSemantic): >+ (WebCore::WHLSL::Parser::parseQualifiers): >+ (WebCore::WHLSL::Parser::parseStructureElement): >+ (WebCore::WHLSL::Parser::parseStructureDefinition): >+ (WebCore::WHLSL::Parser::parseEnumerationDefinition): >+ (WebCore::WHLSL::Parser::parseEnumerationMember): >+ (WebCore::WHLSL::Parser::parseNativeTypeDeclaration): >+ (WebCore::WHLSL::Parser::parseNumThreadsFunctionAttribute): >+ (WebCore::WHLSL::Parser::parseAttributeBlock): >+ (WebCore::WHLSL::Parser::parseParameter): >+ (WebCore::WHLSL::Parser::parseParameters): >+ (WebCore::WHLSL::Parser::parseFunctionDefinition): >+ (WebCore::WHLSL::Parser::parseEntryPointFunctionDeclaration): >+ (WebCore::WHLSL::Parser::parseRegularFunctionDeclaration): >+ (WebCore::WHLSL::Parser::parseOperatorFunctionDeclaration): >+ (WebCore::WHLSL::Parser::parseFunctionDeclaration): >+ (WebCore::WHLSL::Parser::parseNativeFunctionDeclaration): >+ (WebCore::WHLSL::Parser::parseBlock): >+ (WebCore::WHLSL::Parser::parseBlockBody): >+ (WebCore::WHLSL::Parser::parseIfStatement): >+ (WebCore::WHLSL::Parser::parseSwitchStatement): >+ (WebCore::WHLSL::Parser::parseSwitchCase): >+ (WebCore::WHLSL::Parser::parseForLoop): >+ (WebCore::WHLSL::Parser::parseWhileLoop): >+ (WebCore::WHLSL::Parser::parseDoWhileLoop): >+ (WebCore::WHLSL::Parser::parseVariableDeclaration): >+ (WebCore::WHLSL::Parser::parseVariableDeclarations): >+ (WebCore::WHLSL::Parser::parseStatement): >+ (WebCore::WHLSL::Parser::parseEffectfulExpression): >+ (WebCore::WHLSL::Parser::parseEffectfulAssignment): >+ (WebCore::WHLSL::Parser::parseEffectfulPrefix): >+ (WebCore::WHLSL::Parser::parseEffectfulSuffix): >+ (WebCore::WHLSL::Parser::parseLimitedSuffixOperator): >+ (WebCore::WHLSL::Parser::parseSuffixOperator): >+ (WebCore::WHLSL::Parser::parseExpression): >+ (WebCore::WHLSL::Parser::parseTernaryConditional): >+ (WebCore::WHLSL::Parser::parseAssignment): >+ (WebCore::WHLSL::Parser::parsePossibleTernaryConditional): >+ (WebCore::WHLSL::Parser::parsePossibleLogicalBinaryOperation): >+ (WebCore::WHLSL::Parser::parsePossibleRelationalBinaryOperation): >+ (WebCore::WHLSL::Parser::parsePossibleShift): >+ (WebCore::WHLSL::Parser::parsePossibleAdd): >+ (WebCore::WHLSL::Parser::parsePossibleMultiply): >+ (WebCore::WHLSL::Parser::parsePossiblePrefix): >+ (WebCore::WHLSL::Parser::parsePossibleSuffix): >+ (WebCore::WHLSL::Parser::parseCallExpression): >+ (WebCore::WHLSL::Parser::parseTerm): >+ * Modules/webgpu/WHLSL/WHLSLParser.h: >+ (WebCore::WHLSL::Parser::Error::Error): >+ (WebCore::WHLSL::Parser::backtrackingScope): >+ (WebCore::WHLSL::Parser::SuffixExpression::SuffixExpression): >+ (WebCore::WHLSL::Parser::SuffixExpression::operator bool const): >+ > 2019-01-11 Zalan Bujtas <zalan@apple.com> > > [LFC][BFC][MarginCollapsing] Adjust vertical position when box margin collapses through. >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLDotExpression.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLDotExpression.h >index d2c19dbb2dbeca3849a2b4d80188ddedeb72f0ac..0846857e5ce628afb6851732402dffe4791d2b5e 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLDotExpression.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLDotExpression.h >@@ -30,6 +30,7 @@ > #include "WHLSLLexer.h" > #include "WHLSLPropertyAccessExpression.h" > #include <wtf/UniqueRef.h> >+#include <wtf/text/StringConcatenate.h> > > namespace WebCore { > >@@ -54,17 +55,17 @@ public: > > String getFunctionName() const override > { >- return String::format("operator.%s", m_fieldName.utf8().data()); >+ return makeString("operator.", m_fieldName); > } > > String setFunctionName() const override > { >- return String::format("operator.%s=", m_fieldName.utf8().data()); >+ return makeString("operator.%s=", m_fieldName); > } > > String andFunctionName() const override > { >- return String::format("operator&.%s", m_fieldName.utf8().data()); >+ return makeString("operator&.%s", m_fieldName); > } > > String& fieldName() { return m_fieldName; } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFloatLiteralType.cpp b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFloatLiteralType.cpp >index 4680932f6599cfdfdd0c6413c3114577ab5b70a3..4bed3006de153b08731337dcc747c6f22d65fb3f 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFloatLiteralType.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFloatLiteralType.cpp >@@ -38,7 +38,7 @@ namespace AST { > > FloatLiteralType::FloatLiteralType(Lexer::Token&& origin, float value) > : m_value(value) >- , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), String("float", String::ConstructFromLiteral), TypeArguments())) >+ , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), "float"_str, TypeArguments())) > { > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >index ab897740f3f2fdf4c3dcc6be86ef3a0c2d7a4820..25ba6e78a59f7678862b8485048f9dea8f00b79e 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >@@ -54,17 +54,17 @@ public: > > String getFunctionName() const override > { >- return String("operator[]", String::ConstructFromLiteral); >+ return "operator[]"_str; > } > > String setFunctionName() const override > { >- return String("operator&[]", String::ConstructFromLiteral); >+ return "operator&[]"_str; > } > > String andFunctionName() const override > { >- return String("operator[]=", String::ConstructFromLiteral); >+ return "operator[]="_str; > } > > Expression& indexExpression() { return static_cast<Expression&>(m_index); } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIntegerLiteralType.cpp b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIntegerLiteralType.cpp >index 5b451eef5bdd1c1fbdb6d0b1710f28d2c51bb86f..cc7f4ce2a377f4d4c8b8156aca5d48f4ecc99512 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIntegerLiteralType.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIntegerLiteralType.cpp >@@ -36,7 +36,7 @@ namespace AST { > > IntegerLiteralType::IntegerLiteralType(Lexer::Token&& origin, int value) > : m_value(value) >- , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), String("int", String::ConstructFromLiteral), TypeArguments())) >+ , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), "int"_str, TypeArguments())) > { > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteralType.cpp b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteralType.cpp >index eedacf6a6b864f135afb8b6c5df3e63939cf8238..a3387be8d3406c761d178e2e234b6becce79f542 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteralType.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteralType.cpp >@@ -38,7 +38,7 @@ namespace AST { > > UnsignedIntegerLiteralType::UnsignedIntegerLiteralType(Lexer::Token&& origin, unsigned value) > : m_value(value) >- , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), String("uint", String::ConstructFromLiteral), TypeArguments())) >+ , m_preferredType(makeUniqueRef<TypeReference>(WTFMove(origin), "uint"_str, TypeArguments())) > { > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.h >index a418fa1707549834c0b87d271ece90251239ba23..1bb78089b2ed039796913568af138168a6089b40 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.h >@@ -29,6 +29,8 @@ > > #include <wtf/Optional.h> > #include <wtf/Vector.h> >+#include <wtf/text/StringConcatenate.h> >+#include <wtf/text/StringConcatenateNumbers.h> > #include <wtf/text/StringView.h> > #include <wtf/text/WTFString.h> > >@@ -217,7 +219,7 @@ public: > > String errorString(const Token& token, const String& message) > { >- return String::format("Parse error at line %u: %s", token.lineNumber, message.utf8().data()); >+ return makeString("Parse error at line ", token.lineNumber, ": ", message); > } > > private: >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp >index b2d790577a414d6094ca0a81492effbb68bc1b8f..f40453434cb4545dd86b304a7337580710dc4940 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp >@@ -28,12 +28,2562 @@ > > #if ENABLE(WEBGPU) > >+#include <wtf/dtoa.h> > #include <wtf/text/StringBuilder.h> >+#include <wtf/text/StringConcatenate.h> > > namespace WebCore { > > namespace WHLSL { > >+Parser::Parser() >+{ >+} >+ >+// FIXME: Return a better error code from this, and report it to JavaScript. >+auto Parser::parse(Program& program, StringView stringView, Mode mode) -> Optional<Error> >+{ >+ m_lexer = Lexer(stringView); >+ m_mode = mode; >+ >+ while (!m_lexer.isFullyConsumed()) { >+ if (tryType(Lexer::Token::Type::Semicolon)) { >+ m_lexer.consumeToken(); >+ continue; >+ } >+ >+ { >+ auto typeDefinition = backtrackingScope<Expected<AST::TypeDefinition, Error>>([&]() { >+ return parseTypeDefinition(); >+ }); >+ if (typeDefinition) { >+ auto success = program.append(WTFMove(*typeDefinition)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", typeDefinition->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ } >+ >+ { >+ auto structureDefinition = backtrackingScope<Expected<AST::StructureDefinition, Error>>([&]() { >+ return parseStructureDefinition(); >+ }); >+ if (structureDefinition) { >+ auto success = program.append(WTFMove(*structureDefinition)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", structureDefinition->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ } >+ >+ { >+ auto enumerationDefinition = backtrackingScope<Expected<AST::EnumerationDefinition, Error>>([&]() { >+ return parseEnumerationDefinition(); >+ }); >+ if (enumerationDefinition) { >+ auto success = program.append(WTFMove(*enumerationDefinition)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", enumerationDefinition->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ } >+ >+ Optional<Error> error; >+ { >+ auto functionDefinition = backtrackingScope<Expected<AST::FunctionDefinition, Error>>([&]() { >+ return parseFunctionDefinition(); >+ }); >+ if (functionDefinition) { >+ auto success = program.append(WTFMove(*functionDefinition)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", functionDefinition->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ error = functionDefinition.error(); >+ } >+ >+ if (m_mode == Mode::StandardLibrary) { >+ auto nativeFunctionDeclaration = backtrackingScope<Expected<AST::NativeFunctionDeclaration, Error>>([&]() { >+ return parseNativeFunctionDeclaration(); >+ }); >+ if (nativeFunctionDeclaration) { >+ auto success = program.append(WTFMove(*nativeFunctionDeclaration)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", nativeFunctionDeclaration->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ } >+ >+ if (m_mode == Mode::StandardLibrary) { >+ auto nativeTypeDeclaration = backtrackingScope<Expected<AST::NativeTypeDeclaration, Error>>([&]() { >+ return parseNativeTypeDeclaration(); >+ }); >+ if (nativeTypeDeclaration) { >+ auto success = program.append(WTFMove(*nativeTypeDeclaration)); >+ if (!success) { >+ WTFLogAlways("Name Error! %s", nativeTypeDeclaration->name().utf8().data()); >+ return WTF::nullopt; >+ } >+ continue; >+ } >+ } >+ >+ WTFLogAlways("%s", error->error.utf8().data()); >+ return WTFMove(*error); >+ } >+ return WTF::nullopt; >+} >+ >+auto Parser::fail(const String& message) -> Unexpected<Error> >+{ >+ if (auto nextToken = peek()) >+ return Unexpected<Error>(Error(m_lexer.errorString(*nextToken, message))); >+ return Unexpected<Error>(Error(makeString("Cannot lex: ", message))); >+} >+ >+auto Parser::peek() -> Expected<Lexer::Token, Error> { >+ if (auto token = m_lexer.consumeToken()) { >+ m_lexer.unconsumeToken(Lexer::Token(*token)); >+ return *token; >+ } >+ return fail("Cannot consume token"_str); >+} >+ >+Optional<Lexer::Token> Parser::tryType(Lexer::Token::Type type) >+{ >+ if (auto token = m_lexer.consumeToken()) { >+ if (token->type == type) >+ return token; >+ m_lexer.unconsumeToken(Lexer::Token(*token)); >+ } >+ return WTF::nullopt; >+} >+ >+Optional<Lexer::Token> Parser::tryTypes(Vector<Lexer::Token::Type> types) >+{ >+ if (auto token = m_lexer.consumeToken()) { >+ if (std::find(types.begin(), types.end(), token->type) != types.end()) >+ return token; >+ m_lexer.unconsumeToken(Lexer::Token(*token)); >+ } >+ return WTF::nullopt; >+} >+ >+auto Parser::consumeType(Lexer::Token::Type type) -> Expected<Lexer::Token, Error> { >+ if (auto token = m_lexer.consumeToken()) { >+ if (token->type == type) >+ return *token; >+ return fail(makeString("Unexpected token (expected ", Lexer::Token::typeName(type), " got ", Lexer::Token::typeName(token->type), ")")); >+ } >+ return fail(makeString("Cannot consume token (expected ", Lexer::Token::typeName(type), ")")); >+} >+ >+auto Parser::consumeTypes(Vector<Lexer::Token::Type> types) -> Expected<Lexer::Token, Error> { >+ auto buildExpectedString = [&]() -> String { >+ StringBuilder builder; >+ builder.append("["); >+ for (unsigned i = 0; i < types.size(); ++i) { >+ if (i > 0) >+ builder.append(", "); >+ builder.append(Lexer::Token::typeName(types[i])); >+ } >+ builder.append("]"); >+ return builder.toString(); >+ }; >+ >+ if (auto token = m_lexer.consumeToken()) { >+ if (std::find(types.begin(), types.end(), token->type) != types.end()) >+ return *token; >+ return fail(makeString("Unexpected token (expected one of ", buildExpectedString(), " got ", Lexer::Token::typeName(token->type), ")")); >+ } >+ return fail(makeString("Cannot consume token (expected ", buildExpectedString(), ")")); >+} >+ >+static int digitValue(UChar character) >+{ >+ if (character >= '0' && character <= '9') >+ return character - '0'; >+ if (character >= 'a' && character <= 'f') >+ return character - 'a' + 10; >+ return character - 'A' + 10; >+} >+ >+static Expected<int, Parser::Error> intLiteralToInt(StringView text) >+{ >+ bool negate = false; >+ if (text.startsWith("-"_str)) { >+ negate = true; >+ text = text.substring(1); >+ } >+ int base = 10; >+ if (text.startsWith("0x"_str)) { >+ text = text.substring(2); >+ base = 16; >+ } >+ >+ unsigned result = 0; >+ for (auto codePoint : text.codePoints()) { >+ unsigned digit = digitValue(codePoint); >+ auto previous = result; >+ result = result * base + digit; >+ if (result < previous) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("int literal ", text, " is out of bounds"))); >+ } >+ if (negate) { >+ static_assert(std::numeric_limits<long long int>::min() < std::numeric_limits<int>::min(), "long long needs to be bigger than an int"); >+ if (static_cast<long long>(result) > std::abs(static_cast<long long>(std::numeric_limits<int>::min()))) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("int literal ", text, " is out of bounds"))); >+ return { static_cast<int>(static_cast<long long>(result) * 1) }; >+ } >+ if (result > static_cast<unsigned>(std::numeric_limits<int>::max())) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("int literal ", text, " is out of bounds"))); >+ return { static_cast<int>(result) }; >+} >+ >+static Expected<unsigned, Parser::Error> uintLiteralToUint(StringView text) >+{ >+ unsigned base = 10; >+ if (text.startsWith("0x"_str)) { >+ text = text.substring(2); >+ base = 16; >+ } >+ ASSERT(text.endsWith("u"_str)); >+ text = text.substring(0, text.length() - 1); >+ unsigned result = 0; >+ for (auto codePoint : text.codePoints()) { >+ unsigned digit = digitValue(codePoint); >+ auto previous = result; >+ result = result * base + digit; >+ if (result < previous) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("uint literal ", text, " is out of bounds"))); >+ } >+ return { result }; >+} >+ >+static Expected<float, Parser::Error> floatLiteralToFloat(StringView text) >+{ >+ size_t parsedLength; >+ auto result = parseDouble(text, parsedLength); >+ if (parsedLength != text.length()) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("Cannot parse float ", text))); >+ return static_cast<float>(result); >+} >+ >+auto Parser::consumeIntegralLiteral() -> Expected<Variant<int, unsigned>, Error> { >+ auto integralLiteralToken = consumeTypes({ Lexer::Token::Type::IntLiteral, Lexer::Token::Type::UintLiteral }); >+ if (!integralLiteralToken) >+ return Unexpected<Error>(integralLiteralToken.error()); >+ >+ switch (integralLiteralToken->type) { >+ case Lexer::Token::Type::IntLiteral: { >+ auto result = intLiteralToInt(integralLiteralToken->stringView); >+ if (result) >+ return {{ *result }}; >+ return Unexpected<Error>(result.error()); >+ } >+ case Lexer::Token::Type::UintLiteral: { >+ auto result = uintLiteralToUint(integralLiteralToken->stringView); >+ if (result) >+ return {{ *result }}; >+ return Unexpected<Error>(result.error()); >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ >+auto Parser::consumeNonNegativeIntegralLiteral() -> Expected<unsigned, Error> { >+ auto integralLiteral = consumeIntegralLiteral(); >+ if (!integralLiteral) >+ return Unexpected<Error>(integralLiteral.error()); >+ auto result = WTF::visit(WTF::makeVisitor([](int x) -> Optional<unsigned> { >+ if (x < 0) >+ return WTF::nullopt; >+ return x; >+ }, [](unsigned x) -> Optional<unsigned> { >+ return x; >+ }), *integralLiteral); >+ if (result) >+ return *result; >+ return fail("int literal is negative"_str); >+} >+ >+static Expected<unsigned, Parser::Error> recognizeSimpleUnsignedInteger(StringView stringView) >+{ >+ unsigned result = 0; >+ if (stringView.length() < 1) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("Simple unsigned literal ", stringView, " is too short"))); >+ for (auto codePoint : stringView.codePoints()) { >+ if (codePoint < '0' || codePoint > '9') >+ return Unexpected<Parser::Error>(Parser::Error(makeString("Simple unsigned literal ", stringView, " isn't of the form [0-9]+"))); >+ auto previous = result; >+ result = result * 10 + (codePoint - '0'); >+ if (result < previous) >+ return Unexpected<Parser::Error>(Parser::Error(makeString("Simple unsigned literal ", stringView, " is out of bounds"))); >+ } >+ return result; >+} >+ >+auto Parser::parseConstantExpression() -> Expected<AST::ConstantExpression, Error> { >+ auto type = consumeTypes({ >+ Lexer::Token::Type::IntLiteral, >+ Lexer::Token::Type::UintLiteral, >+ Lexer::Token::Type::FloatLiteral, >+ Lexer::Token::Type::Null, >+ Lexer::Token::Type::True, >+ Lexer::Token::Type::False, >+ Lexer::Token::Type::Identifier, >+ }); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ switch (type->type) { >+ case Lexer::Token::Type::IntLiteral: { >+ auto value = intLiteralToInt(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return {{ AST::IntegerLiteral(WTFMove(*type), *value) }}; >+ } >+ case Lexer::Token::Type::UintLiteral: { >+ auto value = uintLiteralToUint(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return {{ AST::UnsignedIntegerLiteral(WTFMove(*type), *value) }}; >+ } >+ case Lexer::Token::Type::FloatLiteral: { >+ auto value = floatLiteralToFloat(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return {{ AST::FloatLiteral(WTFMove(*type), *value) }}; >+ } >+ case Lexer::Token::Type::Null: >+ return { AST::NullLiteral(WTFMove(*type)) }; >+ case Lexer::Token::Type::True: >+ return { AST::BooleanLiteral(WTFMove(*type), true) }; >+ case Lexer::Token::Type::False: >+ return { AST::BooleanLiteral(WTFMove(*type), false) }; >+ case Lexer::Token::Type::Identifier: { >+ auto origin = consumeType(Lexer::Token::Type::FullStop); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ auto next = consumeType(Lexer::Token::Type::Identifier); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ return { AST::ConstantExpressionEnumerationMemberReference(WTFMove(*origin), type->stringView.toString(), next->stringView.toString()) }; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ >+auto Parser::parseTypeArgument() -> Expected<AST::TypeArgument, Error> { >+ auto constantExpression = backtrackingScope<Expected<AST::ConstantExpression, Error>>([&]() { >+ return parseConstantExpression(); >+ }); >+ if (constantExpression) >+ return AST::TypeArgument(WTFMove(*constantExpression)); >+ auto result = consumeType(Lexer::Token::Type::Identifier); >+ if (!result) >+ return Unexpected<Error>(result.error()); >+ return AST::TypeArgument(makeUniqueRef<AST::TypeReference>(Lexer::Token(*result), result->stringView.toString(), AST::TypeArguments())); >+} >+ >+auto Parser::parseTypeArguments() -> Expected<AST::TypeArguments, Error> { >+ auto typeArguments = backtrackingScope<Optional<AST::TypeArguments>>([&]() -> Optional<AST::TypeArguments> { >+ auto lessThanSign = consumeType(Lexer::Token::Type::LessThanSign); >+ if (!lessThanSign) >+ return WTF::nullopt; >+ AST::TypeArguments typeArguments; >+ auto typeArgument = parseTypeArgument(); >+ if (!typeArgument) >+ return WTF::nullopt; >+ typeArguments.append(WTFMove(*typeArgument)); >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto typeArgument = parseTypeArgument(); >+ if (!typeArgument) >+ return WTF::nullopt; >+ typeArguments.append(WTFMove(*typeArgument)); >+ } >+ auto greaterThanSign = consumeType(Lexer::Token::Type::GreaterThanSign); >+ if (!greaterThanSign) >+ return WTF::nullopt; >+ return typeArguments; >+ }); >+ if (typeArguments) >+ return WTFMove(*typeArguments); >+ >+ typeArguments = backtrackingScope<Optional<AST::TypeArguments>>([&]() -> Optional<AST::TypeArguments> { >+ auto lessThanSign = consumeType(Lexer::Token::Type::LessThanSign); >+ if (!lessThanSign) >+ return WTF::nullopt; >+ auto greaterThanSign = consumeType(Lexer::Token::Type::GreaterThanSign); >+ if (!greaterThanSign) >+ return WTF::nullopt; >+ return {{ }}; >+ }); >+ if (typeArguments) >+ return WTFMove(*typeArguments); >+ >+ return AST::TypeArguments(); >+} >+ >+auto Parser::parseTypeSuffixAbbreviated() -> Expected<TypeSuffixAbbreviated, Error> { >+ auto token = consumeTypes({ Lexer::Token::Type::Star, Lexer::Token::Type::SquareBracketPair, Lexer::Token::Type::LeftSquareBracket }); >+ if (!token) >+ return Unexpected<Error>(token.error()); >+ if (token->type == Lexer::Token::Type::LeftSquareBracket) { >+ auto numElements = consumeNonNegativeIntegralLiteral(); >+ if (!numElements) >+ return Unexpected<Error>(numElements.error()); >+ auto rightSquareBracket = consumeType(Lexer::Token::Type::RightSquareBracket); >+ if (!rightSquareBracket) >+ return Unexpected<Error>(rightSquareBracket.error()); >+ return {{ *token, *numElements }}; >+ } >+ return {{ *token, WTF::nullopt }}; >+} >+ >+auto Parser::parseTypeSuffixNonAbbreviated() -> Expected<TypeSuffixNonAbbreviated, Error> { >+ auto token = consumeTypes({ Lexer::Token::Type::Star, Lexer::Token::Type::SquareBracketPair, Lexer::Token::Type::LeftSquareBracket }); >+ if (!token) >+ return Unexpected<Error>(token.error()); >+ if (token->type == Lexer::Token::Type::LeftSquareBracket) { >+ auto numElements = consumeNonNegativeIntegralLiteral(); >+ if (!numElements) >+ return Unexpected<Error>(numElements.error()); >+ auto rightSquareBracket = consumeType(Lexer::Token::Type::RightSquareBracket); >+ if (!rightSquareBracket) >+ return Unexpected<Error>(rightSquareBracket.error()); >+ return {{ *token, WTF::nullopt, *numElements }}; >+ } >+ auto addressSpaceToken = consumeTypes({ Lexer::Token::Type::Constant, Lexer::Token::Type::Device, Lexer::Token::Type::Threadgroup, Lexer::Token::Type::Thread}); >+ if (!addressSpaceToken) >+ return Unexpected<Error>(addressSpaceToken.error()); >+ AST::ReferenceType::AddressSpace addressSpace; >+ switch (addressSpaceToken->type) { >+ case Lexer::Token::Type::Constant: >+ addressSpace = AST::ReferenceType::AddressSpace::Constant; >+ break; >+ case Lexer::Token::Type::Device: >+ addressSpace = AST::ReferenceType::AddressSpace::Device; >+ break; >+ case Lexer::Token::Type::Threadgroup: >+ addressSpace = AST::ReferenceType::AddressSpace::Threadgroup; >+ break; >+ case Lexer::Token::Type::Thread: >+ addressSpace = AST::ReferenceType::AddressSpace::Thread; >+ break; >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ return {{ *token, { addressSpace }, WTF::nullopt }}; >+} >+ >+auto Parser::parseAddressSpaceType() -> Expected<UniqueRef<AST::UnnamedType>, Error> { >+ auto addressSpaceToken = consumeTypes({ Lexer::Token::Type::Constant, Lexer::Token::Type::Device, Lexer::Token::Type::Threadgroup, Lexer::Token::Type::Thread}); >+ if (!addressSpaceToken) >+ return Unexpected<Error>(addressSpaceToken.error()); >+ AST::ReferenceType::AddressSpace addressSpace; >+ switch (addressSpaceToken->type) { >+ case Lexer::Token::Type::Constant: >+ addressSpace = AST::ReferenceType::AddressSpace::Constant; >+ break; >+ case Lexer::Token::Type::Device: >+ addressSpace = AST::ReferenceType::AddressSpace::Device; >+ break; >+ case Lexer::Token::Type::Threadgroup: >+ addressSpace = AST::ReferenceType::AddressSpace::Threadgroup; >+ break; >+ case Lexer::Token::Type::Thread: >+ addressSpace = AST::ReferenceType::AddressSpace::Thread; >+ break; >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ auto typeArguments = parseTypeArguments(); >+ if (!typeArguments) >+ return Unexpected<Error>(typeArguments.error()); >+ >+ auto constructTypeFromSuffixAbbreviated = [&](const TypeSuffixAbbreviated& typeSuffixAbbreviated, UniqueRef<AST::UnnamedType>&& previous) -> Optional<UniqueRef<AST::UnnamedType>> { >+ switch (typeSuffixAbbreviated.token.type) { >+ case Lexer::Token::Type::Star: >+ return { makeUniqueRef<AST::PointerType>(Lexer::Token(typeSuffixAbbreviated.token), addressSpace, WTFMove(previous)) }; >+ case Lexer::Token::Type::SquareBracketPair: >+ return { makeUniqueRef<AST::ArrayReferenceType>(Lexer::Token(typeSuffixAbbreviated.token), addressSpace, WTFMove(previous)) }; >+ case Lexer::Token::Type::LeftSquareBracket: >+ return { makeUniqueRef<AST::ArrayType>(Lexer::Token(typeSuffixAbbreviated.token), WTFMove(previous), *typeSuffixAbbreviated.numElements) }; >+ default: >+ ASSERT_NOT_REACHED(); >+ return WTF::nullopt; >+ } >+ }; >+ >+ auto firstTypeSuffixAbbreviated = parseTypeSuffixAbbreviated(); >+ if (!firstTypeSuffixAbbreviated) >+ return Unexpected<Error>(firstTypeSuffixAbbreviated.error()); >+ UniqueRef<AST::UnnamedType> result = makeUniqueRef<AST::TypeReference>(WTFMove(*addressSpaceToken), name->stringView.toString(), WTFMove(*typeArguments)); >+ auto next = constructTypeFromSuffixAbbreviated(*firstTypeSuffixAbbreviated, WTFMove(result)); >+ if (!next) >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ result = WTFMove(*next); >+ while (true) { >+ auto typeSuffixAbbreviated = backtrackingScope<Expected<TypeSuffixAbbreviated, Error>>([&]() { >+ return parseTypeSuffixAbbreviated(); >+ }); >+ if (!typeSuffixAbbreviated) >+ break; >+ // FIXME: The nesting here might be in the wrong order. >+ next = constructTypeFromSuffixAbbreviated(*typeSuffixAbbreviated, WTFMove(result)); >+ if (!next) >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ result = WTFMove(*next); >+ } >+ >+ return WTFMove(result); >+} >+ >+auto Parser::parseNonAddressSpaceType() -> Expected<UniqueRef<AST::UnnamedType>, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ auto typeArguments = parseTypeArguments(); >+ if (!typeArguments) >+ return Unexpected<Error>(typeArguments.error()); >+ >+ auto constructTypeFromSuffixNonAbbreviated = [&](const TypeSuffixNonAbbreviated& typeSuffixNonAbbreviated, UniqueRef<AST::UnnamedType>&& previous) -> Optional<UniqueRef<AST::UnnamedType>> { >+ switch (typeSuffixNonAbbreviated.token.type) { >+ case Lexer::Token::Type::Star: >+ return { makeUniqueRef<AST::PointerType>(Lexer::Token(typeSuffixNonAbbreviated.token), *typeSuffixNonAbbreviated.addressSpace, WTFMove(previous)) }; >+ case Lexer::Token::Type::SquareBracketPair: >+ return { makeUniqueRef<AST::ArrayReferenceType>(Lexer::Token(typeSuffixNonAbbreviated.token), *typeSuffixNonAbbreviated.addressSpace, WTFMove(previous)) }; >+ case Lexer::Token::Type::LeftSquareBracket: >+ return { makeUniqueRef<AST::ArrayType>(Lexer::Token(typeSuffixNonAbbreviated.token), WTFMove(previous), *typeSuffixNonAbbreviated.numElements) }; >+ default: >+ ASSERT_NOT_REACHED(); >+ return WTF::nullopt; >+ } >+ }; >+ >+ UniqueRef<AST::UnnamedType> result = makeUniqueRef<AST::TypeReference>(WTFMove(*origin), name->stringView.toString(), WTFMove(*typeArguments)); >+ while (true) { >+ auto typeSuffixNonAbbreviated = backtrackingScope<Expected<TypeSuffixNonAbbreviated, Error>>([&]() { >+ return parseTypeSuffixNonAbbreviated(); >+ }); >+ if (!typeSuffixNonAbbreviated) >+ break; >+ // FIXME: The nesting here might be in the wrong order. >+ auto next = constructTypeFromSuffixNonAbbreviated(*typeSuffixNonAbbreviated, WTFMove(result)); >+ if (!next) >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ result = WTFMove(*next); >+ } >+ >+ return WTFMove(result); >+} >+ >+auto Parser::parseType() -> Expected<UniqueRef<AST::UnnamedType>, Error> { >+ auto type = backtrackingScope<Expected<UniqueRef<AST::UnnamedType>, Error>>([&]() { >+ return parseAddressSpaceType(); >+ }); >+ if (type) >+ return type; >+ >+ type = backtrackingScope<Expected<UniqueRef<AST::UnnamedType>, Error>>([&]() { >+ return parseNonAddressSpaceType(); >+ }); >+ if (type) >+ return type; >+ >+ return Unexpected<Error>(type.error()); >+} >+ >+auto Parser::parseTypeDefinition() -> Expected<AST::TypeDefinition, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Typedef); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ auto equals = consumeType(Lexer::Token::Type::EqualsSign); >+ if (!equals) >+ return Unexpected<Error>(equals.error()); >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ return AST::TypeDefinition(WTFMove(*origin), name->stringView.toString(), WTFMove(*type)); >+} >+ >+auto Parser::parseBuiltInSemantic() -> Expected<AST::BuiltInSemantic, Error> { >+ auto origin = consumeTypes({ >+ Lexer::Token::Type::SVInstanceID, >+ Lexer::Token::Type::SVVertexID, >+ Lexer::Token::Type::PSize, >+ Lexer::Token::Type::SVPosition, >+ Lexer::Token::Type::SVIsFrontFace, >+ Lexer::Token::Type::SVSampleIndex, >+ Lexer::Token::Type::SVInnerCoverage, >+ Lexer::Token::Type::SVTarget, >+ Lexer::Token::Type::SVDepth, >+ Lexer::Token::Type::SVCoverage, >+ Lexer::Token::Type::SVDispatchThreadID, >+ Lexer::Token::Type::SVGroupID, >+ Lexer::Token::Type::SVGroupIndex, >+ Lexer::Token::Type::SVGroupThreadID}); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ switch (origin->type) { >+ case Lexer::Token::Type::SVInstanceID: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVInstanceID); >+ case Lexer::Token::Type::SVVertexID: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVVertexID); >+ case Lexer::Token::Type::PSize: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::PSize); >+ case Lexer::Token::Type::SVPosition: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVPosition); >+ case Lexer::Token::Type::SVIsFrontFace: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVIsFrontFace); >+ case Lexer::Token::Type::SVSampleIndex: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVSampleIndex); >+ case Lexer::Token::Type::SVInnerCoverage: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVInnerCoverage); >+ case Lexer::Token::Type::SVTarget: { >+ auto target = consumeNonNegativeIntegralLiteral(); >+ if (!target) >+ return Unexpected<Error>(target.error()); >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVTarget, *target); >+ } >+ case Lexer::Token::Type::SVDepth: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVDepth); >+ case Lexer::Token::Type::SVCoverage: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVCoverage); >+ case Lexer::Token::Type::SVDispatchThreadID: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVDispatchThreadID); >+ case Lexer::Token::Type::SVGroupID: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVGroupID); >+ case Lexer::Token::Type::SVGroupIndex: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVGroupIndex); >+ case Lexer::Token::Type::SVGroupThreadID: >+ return AST::BuiltInSemantic(WTFMove(*origin), AST::BuiltInSemantic::Variable::SVGroupThreadID); >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ >+auto Parser::parseResourceSemantic() -> Expected<AST::ResourceSemantic, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Register); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto info = consumeType(Lexer::Token::Type::Identifier); >+ if (!info) >+ return Unexpected<Error>(info.error()); >+ if (info->stringView.length() < 2 || (info->stringView[0] != 'u' >+ && info->stringView[0] != 't' >+ && info->stringView[0] != 'b' >+ && info->stringView[0] != 's')) >+ return Unexpected<Error>(Error(makeString(info->stringView.substring(0, 1), " is not a known resource type ('u', 't', 'b', or 's')"))); >+ >+ AST::ResourceSemantic::Mode mode; >+ switch (info->stringView[0]) { >+ case 'u': >+ mode = AST::ResourceSemantic::Mode::UnorderedAccessView; >+ break; >+ case 't': >+ mode = AST::ResourceSemantic::Mode::Texture; >+ break; >+ case 'b': >+ mode = AST::ResourceSemantic::Mode::Buffer; >+ break; >+ case 's': >+ mode = AST::ResourceSemantic::Mode::Sampler; >+ break; >+ } >+ >+ auto index = recognizeSimpleUnsignedInteger(info->stringView.substring(1)); >+ if (!index) >+ return Unexpected<Error>(index.error()); >+ >+ unsigned space = 0; >+ if (tryType(Lexer::Token::Type::Comma)) { >+ auto spaceToken = consumeType(Lexer::Token::Type::Identifier); >+ if (!spaceToken) >+ return Unexpected<Error>(spaceToken.error()); >+ auto prefix = "space"_str; >+ if (!spaceToken->stringView.startsWith(StringView(prefix))) >+ return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceToken->stringView, " needs be of the form 'space0'"))); >+ if (spaceToken->stringView.length() <= prefix.length()) >+ return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceToken->stringView, " needs be of the form 'space0'"))); >+ auto spaceValue = recognizeSimpleUnsignedInteger(spaceToken->stringView.substring(prefix.length())); >+ if (!spaceValue) >+ return Unexpected<Error>(spaceValue.error()); >+ space = *spaceValue; >+ } >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return AST::ResourceSemantic(WTFMove(*origin), mode, *index, space); >+} >+ >+auto Parser::parseSpecializationConstantSemantic() -> Expected<AST::SpecializationConstantSemantic, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Specialized); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ return AST::SpecializationConstantSemantic(WTFMove(*origin)); >+} >+ >+auto Parser::parseStageInOutSemantic() -> Expected<AST::StageInOutSemantic, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Attribute); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto index = consumeNonNegativeIntegralLiteral(); >+ if (!index) >+ return Unexpected<Error>(index.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return AST::StageInOutSemantic(WTFMove(*origin), *index); >+} >+ >+auto Parser::parseSemantic() -> Expected<AST::Semantic, Error> { >+ auto builtInSemantic = backtrackingScope<Expected<AST::BuiltInSemantic, Error>>([&]() { >+ return parseBuiltInSemantic(); >+ }); >+ if (builtInSemantic) >+ return AST::Semantic(WTFMove(*builtInSemantic)); >+ >+ auto resourceSemantic = backtrackingScope<Expected<AST::ResourceSemantic, Error>>([&]() { >+ return parseResourceSemantic(); >+ }); >+ if (resourceSemantic) >+ return AST::Semantic(WTFMove(*resourceSemantic)); >+ >+ auto specializationConstantSemantic = backtrackingScope<Expected<AST::SpecializationConstantSemantic, Error>>([&]() { >+ return parseSpecializationConstantSemantic(); >+ }); >+ if (specializationConstantSemantic) >+ return AST::Semantic(WTFMove(*specializationConstantSemantic)); >+ >+ auto stageInOutSemantic = backtrackingScope<Expected<AST::StageInOutSemantic, Error>>([&]() { >+ return parseStageInOutSemantic(); >+ }); >+ if (stageInOutSemantic) >+ return AST::Semantic(WTFMove(*stageInOutSemantic)); >+ >+ return Unexpected<Error>(stageInOutSemantic.error()); >+} >+AST::Qualifiers Parser::parseQualifiers() >+{ >+ AST::Qualifiers qualifiers; >+ while (true) { >+ if (auto next = tryType(Lexer::Token::Type::Qualifier)) { >+ if ("nointerpolation" == next->stringView) >+ qualifiers.append(AST::Qualifier::Nointerpolation); >+ else if ("noperspective" == next->stringView) >+ qualifiers.append(AST::Qualifier::Noperspective); >+ else if ("uniform" == next->stringView) >+ qualifiers.append(AST::Qualifier::Uniform); >+ else if ("centroid" == next->stringView) >+ qualifiers.append(AST::Qualifier::Centroid); >+ else if ("sample" == next->stringView) >+ qualifiers.append(AST::Qualifier::Sample); >+ else >+ ASSERT_NOT_REACHED(); >+ } else >+ break; >+ } >+ return qualifiers; >+} >+ >+auto Parser::parseStructureElement() -> Expected<AST::StructureElement, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ AST::Qualifiers qualifiers = parseQualifiers(); >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::StructureElement(WTFMove(*origin), WTFMove(qualifiers), WTFMove(*type), name->stringView.toString(), WTFMove(*semantic)); >+ } >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::StructureElement(WTFMove(*origin), WTFMove(qualifiers), WTFMove(*type), name->stringView.toString(), WTF::nullopt); >+} >+ >+auto Parser::parseStructureDefinition() -> Expected<AST::StructureDefinition, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Struct); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ auto leftCurlyBracket = consumeType(Lexer::Token::Type::LeftCurlyBracket); >+ if (!leftCurlyBracket) >+ return Unexpected<Error>(leftCurlyBracket.error()); >+ >+ AST::StructureElements structureElements; >+ while (true) { >+ auto structureElement = backtrackingScope<Expected<AST::StructureElement, Error>>([&]() { >+ return parseStructureElement(); >+ }); >+ if (structureElement) >+ structureElements.append(WTFMove(*structureElement)); >+ else >+ break; >+ } >+ >+ auto rightCurlyBracket = consumeType(Lexer::Token::Type::RightCurlyBracket); >+ if (!rightCurlyBracket) >+ return Unexpected<Error>(rightCurlyBracket.error()); >+ >+ return AST::StructureDefinition(WTFMove(*origin), name->stringView.toString(), WTFMove(structureElements)); >+} >+ >+auto Parser::parseEnumerationDefinition() -> Expected<AST::EnumerationDefinition, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Enum); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ Optional<UniqueRef<AST::UnnamedType>> type; >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto parsedType = parseType(); >+ if (!parsedType) >+ return Unexpected<Error>(parsedType.error()); >+ type = WTFMove(*parsedType); >+ } >+ >+ auto leftCurlyBracket = consumeType(Lexer::Token::Type::LeftCurlyBracket); >+ if (!leftCurlyBracket) >+ return Unexpected<Error>(leftCurlyBracket.error()); >+ >+ auto firstEnumerationMember = parseEnumerationMember(); >+ if (!firstEnumerationMember) >+ return Unexpected<Error>(firstEnumerationMember.error()); >+ >+ AST::EnumerationDefinition result(WTFMove(*origin), name->stringView.toString(), WTFMove(type)); >+ auto success = result.add(WTFMove(*firstEnumerationMember)); >+ if (!success) >+ return fail("Cannot add enumeration member"_str); >+ >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto member = parseEnumerationMember(); >+ if (!member) >+ return Unexpected<Error>(member.error()); >+ success = result.add(WTFMove(*member)); >+ if (!success) >+ return fail("Cannot add enumeration member"_str); >+ } >+ >+ auto rightCurlyBracket = consumeType(Lexer::Token::Type::RightCurlyBracket); >+ if (!rightCurlyBracket) >+ return Unexpected<Error>(rightCurlyBracket.error()); >+ >+ return WTFMove(result); >+} >+ >+auto Parser::parseEnumerationMember() -> Expected<AST::EnumerationMember, Error> { >+ auto identifier = consumeType(Lexer::Token::Type::Identifier); >+ if (!identifier) >+ return Unexpected<Error>(identifier.error()); >+ auto name = identifier->stringView.toString(); >+ >+ if (tryType(Lexer::Token::Type::EqualsSign)) { >+ auto constantExpression = parseConstantExpression(); >+ if (!constantExpression) >+ return Unexpected<Error>(constantExpression.error()); >+ return AST::EnumerationMember(Lexer::Token(*identifier), WTFMove(name), WTFMove(*constantExpression)); >+ } >+ return AST::EnumerationMember(Lexer::Token(*identifier), WTFMove(name)); >+} >+ >+auto Parser::parseNativeTypeDeclaration() -> Expected<AST::NativeTypeDeclaration, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Native); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto parsedTypedef = consumeType(Lexer::Token::Type::Typedef); >+ if (!parsedTypedef) >+ return Unexpected<Error>(parsedTypedef.error()); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ auto typeArguments = parseTypeArguments(); >+ if (!typeArguments) >+ return Unexpected<Error>(typeArguments.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::NativeTypeDeclaration(WTFMove(*origin), name->stringView.toString(), WTFMove(*typeArguments)); >+} >+ >+auto Parser::parseNumThreadsFunctionAttribute() -> Expected<AST::NumThreadsFunctionAttribute, Error> { >+ auto origin = consumeType(Lexer::Token::Type::NumThreads); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto width = consumeNonNegativeIntegralLiteral(); >+ if (!width) >+ return Unexpected<Error>(width.error()); >+ >+ auto comma = consumeType(Lexer::Token::Type::Comma); >+ if (!comma) >+ return Unexpected<Error>(comma.error()); >+ >+ auto height = consumeNonNegativeIntegralLiteral(); >+ if (!height) >+ return Unexpected<Error>(height.error()); >+ >+ comma = consumeType(Lexer::Token::Type::Comma); >+ if (!comma) >+ return Unexpected<Error>(comma.error()); >+ >+ auto depth = consumeNonNegativeIntegralLiteral(); >+ if (!depth) >+ return Unexpected<Error>(depth.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return AST::NumThreadsFunctionAttribute(WTFMove(*origin), *width, *height, *depth); >+} >+ >+auto Parser::parseAttributeBlock() -> Expected<AST::AttributeBlock, Error> { >+ auto leftSquareBracket = consumeType(Lexer::Token::Type::LeftSquareBracket); >+ if (!leftSquareBracket) >+ return Unexpected<Error>(leftSquareBracket.error()); >+ >+ AST::AttributeBlock result; >+ >+ while (true) { >+ auto numThreadsFunctionAttribute = backtrackingScope<Expected<AST::NumThreadsFunctionAttribute, Error>>([&]() { >+ return parseNumThreadsFunctionAttribute(); >+ }); >+ if (numThreadsFunctionAttribute) { >+ result.append(WTFMove(*numThreadsFunctionAttribute)); >+ continue; >+ } >+ >+ break; >+ } >+ >+ auto rightSquareBracket = consumeType(Lexer::Token::Type::RightSquareBracket); >+ if (!rightSquareBracket) >+ return Unexpected<Error>(rightSquareBracket.error()); >+ >+ return WTFMove(result); >+} >+ >+auto Parser::parseParameter() -> Expected<AST::VariableDeclaration, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ AST::Qualifiers qualifiers = parseQualifiers(); >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ String name; >+ if (auto token = tryType(Lexer::Token::Type::Identifier)) >+ name = token->stringView.toString(); >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), Optional<UniqueRef<AST::UnnamedType>>(WTFMove(*type)), WTFMove(name), WTFMove(*semantic), WTF::nullopt); >+ } >+ >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), { WTFMove(*type) }, WTFMove(name), WTF::nullopt, WTF::nullopt); >+} >+ >+auto Parser::parseParameters() -> Expected<AST::VariableDeclarations, Error> { >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ AST::VariableDeclarations parameters; >+ if (tryType(Lexer::Token::Type::RightParenthesis)) >+ return WTFMove(parameters); >+ >+ auto firstParameter = parseParameter(); >+ if (!firstParameter) >+ return Unexpected<Error>(firstParameter.error()); >+ parameters.append(WTFMove(*firstParameter)); >+ >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto parameter = parseParameter(); >+ if (!parameter) >+ return Unexpected<Error>(parameter.error()); >+ parameters.append(WTFMove(*parameter)); >+ } >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return WTFMove(parameters); >+} >+ >+auto Parser::parseFunctionDefinition() -> Expected<AST::FunctionDefinition, Error> { >+ bool restricted = static_cast<bool>(tryType(Lexer::Token::Type::Restricted)); >+ >+ auto functionDeclaration = parseFunctionDeclaration(); >+ if (!functionDeclaration) >+ return Unexpected<Error>(functionDeclaration.error()); >+ >+ auto block = parseBlock(); >+ if (!block) >+ return Unexpected<Error>(block.error()); >+ >+ return AST::FunctionDefinition(WTFMove(*functionDeclaration), WTFMove(*block), restricted); >+} >+ >+auto Parser::parseEntryPointFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ AST::AttributeBlock attributeBlock; >+ AST::FunctionDeclaration::EntryPointType entryPointType; >+ >+ auto parsedAttributeBlock = backtrackingScope<Expected<AST::AttributeBlock, Error>>([&]() { >+ return parseAttributeBlock(); >+ }); >+ if (parsedAttributeBlock) { >+ auto compute = consumeType(Lexer::Token::Type::Compute); >+ if (!compute) >+ return Unexpected<Error>(compute.error()); >+ attributeBlock = WTFMove(*parsedAttributeBlock); >+ entryPointType = AST::FunctionDeclaration::EntryPointType::Compute; >+ } else { >+ auto type = consumeTypes({ Lexer::Token::Type::Vertex, Lexer::Token::Type::Fragment }); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ switch (origin->type) { >+ case Lexer::Token::Type::Vertex: >+ entryPointType = AST::FunctionDeclaration::EntryPointType::Vertex; >+ break; >+ case Lexer::Token::Type::Fragment: >+ entryPointType = AST::FunctionDeclaration::EntryPointType::Fragment; >+ break; >+ default: >+ ASSERT_NOT_REACHED(); >+ entryPointType = AST::FunctionDeclaration::EntryPointType::Vertex; >+ } >+ } >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ auto parameters = parseParameters(); >+ if (!parameters) >+ return Unexpected<Error>(parameters.error()); >+ >+ bool isOperator = false; >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ return AST::FunctionDeclaration(WTFMove(*origin), WTFMove(attributeBlock), entryPointType, WTFMove(*type), name->stringView.toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator); >+ } >+ >+ return AST::FunctionDeclaration(WTFMove(*origin), WTFMove(attributeBlock), entryPointType, WTFMove(*type), name->stringView.toString(), WTFMove(*parameters), WTF::nullopt, isOperator); >+} >+ >+auto Parser::parseRegularFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ auto name = consumeTypes({ Lexer::Token::Type::Identifier, Lexer::Token::Type::OperatorName }); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ auto isOperator = name->type == Lexer::Token::Type::OperatorName; >+ >+ auto parameters = parseParameters(); >+ if (!parameters) >+ return Unexpected<Error>(parameters.error()); >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ return AST::FunctionDeclaration(WTFMove(*origin), { }, WTF::nullopt, WTFMove(*type), name->stringView.toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator); >+ } >+ >+ return AST::FunctionDeclaration(WTFMove(*origin), { }, WTF::nullopt, WTFMove(*type), name->stringView.toString(), WTFMove(*parameters), WTF::nullopt, isOperator); >+} >+ >+auto Parser::parseOperatorFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Operator); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ auto parameters = parseParameters(); >+ if (!parameters) >+ return Unexpected<Error>(parameters.error()); >+ >+ bool isOperator = true; >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ return AST::FunctionDeclaration(WTFMove(*origin), { }, WTF::nullopt, WTFMove(*type), "operator cast"_str, WTFMove(*parameters), WTFMove(*semantic), isOperator); >+ } >+ >+ return AST::FunctionDeclaration(WTFMove(*origin), { }, WTF::nullopt, WTFMove(*type), "operator cast"_str, WTFMove(*parameters), WTF::nullopt, isOperator); >+} >+ >+auto Parser::parseFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error> { >+ auto entryPointFunctionDeclaration = backtrackingScope<Expected<AST::FunctionDeclaration, Error>>([&]() { >+ return parseEntryPointFunctionDeclaration(); >+ }); >+ if (entryPointFunctionDeclaration) >+ return WTFMove(*entryPointFunctionDeclaration); >+ >+ auto regularFunctionDeclaration = backtrackingScope<Expected<AST::FunctionDeclaration, Error>>([&]() { >+ return parseRegularFunctionDeclaration(); >+ }); >+ if (regularFunctionDeclaration) >+ return WTFMove(*regularFunctionDeclaration); >+ >+ auto operatorFunctionDeclaration = backtrackingScope<Expected<AST::FunctionDeclaration, Error>>([&]() { >+ return parseOperatorFunctionDeclaration(); >+ }); >+ if (operatorFunctionDeclaration) >+ return WTFMove(*operatorFunctionDeclaration); >+ >+ return Unexpected<Error>(operatorFunctionDeclaration.error()); >+} >+ >+auto Parser::parseNativeFunctionDeclaration() -> Expected<AST::NativeFunctionDeclaration, Error> { >+ Optional<Lexer::Token> origin; >+ >+ bool restricted = false; >+ if (auto restrictedValue = tryType(Lexer::Token::Type::Restricted)) { >+ origin = *restrictedValue; >+ restricted = true; >+ } >+ >+ auto native = consumeType(Lexer::Token::Type::Native); >+ if (!native) >+ return Unexpected<Error>(native.error()); >+ if (!origin) >+ origin = *native; >+ >+ auto functionDeclaration = parseFunctionDeclaration(); >+ if (!functionDeclaration) >+ return Unexpected<Error>(functionDeclaration.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::NativeFunctionDeclaration(WTFMove(*functionDeclaration), restricted); >+} >+ >+auto Parser::parseBlock() -> Expected<AST::Block, Error> { >+ auto origin = consumeType(Lexer::Token::Type::LeftCurlyBracket); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto result = parseBlockBody(WTFMove(*origin)); >+ >+ auto rightCurlyBracket = consumeType(Lexer::Token::Type::RightCurlyBracket); >+ if (!rightCurlyBracket) >+ return Unexpected<Error>(rightCurlyBracket.error()); >+ >+ return WTFMove(result); >+} >+ >+AST::Block Parser::parseBlockBody(Lexer::Token&& origin) >+{ >+ AST::Statements statements; >+ while (true) { >+ auto statement = backtrackingScope<Expected<UniqueRef<AST::Statement>, Error>>([&]() { >+ return parseStatement(); >+ }); >+ if (statement) >+ statements.append(WTFMove(*statement)); >+ else >+ break; >+ } >+ return AST::Block(WTFMove(origin), WTFMove(statements)); >+} >+ >+auto Parser::parseIfStatement() -> Expected<AST::IfStatement, Error> { >+ auto origin = consumeType(Lexer::Token::Type::If); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto conditional = parseExpression(); >+ if (!conditional) >+ return Unexpected<Error>(conditional.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ auto body = parseStatement(); >+ if (!body) >+ return Unexpected<Error>(body.error()); >+ >+ Optional<UniqueRef<AST::Statement>> elseBody; >+ if (tryType(Lexer::Token::Type::Else)) { >+ auto parsedElseBody = parseStatement(); >+ if (!parsedElseBody) >+ return Unexpected<Error>(parsedElseBody.error()); >+ elseBody = WTFMove(*parsedElseBody); >+ } >+ >+ Vector<UniqueRef<AST::Expression>> castArguments; >+ castArguments.append(WTFMove(*conditional)); >+ auto boolCast = makeUniqueRef<AST::CallExpression>(Lexer::Token(*origin), "bool"_str, WTFMove(castArguments)); >+ return AST::IfStatement(WTFMove(*origin), WTFMove(boolCast), WTFMove(*body), WTFMove(elseBody)); >+} >+ >+auto Parser::parseSwitchStatement() -> Expected<AST::SwitchStatement, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Switch); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto value = parseExpression(); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ auto leftCurlyBracket = consumeType(Lexer::Token::Type::LeftCurlyBracket); >+ if (!leftCurlyBracket) >+ return Unexpected<Error>(leftCurlyBracket.error()); >+ >+ Vector<AST::SwitchCase> switchCases; >+ while (true) { >+ auto switchCase = backtrackingScope<Expected<AST::SwitchCase, Error>>([&]() { >+ return parseSwitchCase(); >+ }); >+ if (switchCase) >+ switchCases.append(WTFMove(*switchCase)); >+ else >+ break; >+ } >+ >+ auto rightCurlyBracket = consumeType(Lexer::Token::Type::RightCurlyBracket); >+ if (!rightCurlyBracket) >+ return Unexpected<Error>(rightCurlyBracket.error()); >+ >+ return AST::SwitchStatement(WTFMove(*origin), WTFMove(*value), WTFMove(switchCases)); >+} >+ >+auto Parser::parseSwitchCase() -> Expected<AST::SwitchCase, Error> { >+ auto origin = consumeTypes({ Lexer::Token::Type::Case, Lexer::Token::Type::Default }); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ switch (origin->type) { >+ case Lexer::Token::Type::Case: { >+ auto value = parseConstantExpression(); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ >+ auto origin = consumeType(Lexer::Token::Type::Colon); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto block = parseBlockBody(Lexer::Token(*origin)); >+ >+ return AST::SwitchCase(WTFMove(*origin), WTFMove(*value), WTFMove(block)); >+ } >+ case Lexer::Token::Type::Default: { >+ auto origin = consumeType(Lexer::Token::Type::Colon); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto block = parseBlockBody(Lexer::Token(*origin)); >+ >+ return AST::SwitchCase(WTFMove(*origin), WTF::nullopt, WTFMove(block)); >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ >+auto Parser::parseForLoop() -> Expected<AST::ForLoop, Error> { >+ auto origin = consumeType(Lexer::Token::Type::For); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto parseRemainder = [&](Variant<AST::VariableDeclarationsStatement, UniqueRef<AST::Expression>>&& initialization) -> Expected<AST::ForLoop, Error> { >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ auto condition = backtrackingScope<Optional<UniqueRef<AST::Expression>>>([&]() -> Optional<UniqueRef<AST::Expression>> { >+ if (auto expression = parseExpression()) >+ return { WTFMove(*expression) }; >+ return WTF::nullopt; >+ }); >+ >+ semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ auto increment = backtrackingScope<Optional<UniqueRef<AST::Expression>>>([&]() -> Optional<UniqueRef<AST::Expression>> { >+ if (auto expression = parseExpression()) >+ return { WTFMove(*expression) }; >+ return WTF::nullopt; >+ }); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ auto body = parseStatement(); >+ if (!body) >+ return Unexpected<Error>(body.error()); >+ >+ return AST::ForLoop(WTFMove(*origin), WTFMove(initialization), WTFMove(condition), WTFMove(increment), WTFMove(*body)); >+ }; >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto variableDeclarations = backtrackingScope<Expected<AST::VariableDeclarationsStatement, Error>>([&]() { >+ return parseVariableDeclarations(); >+ }); >+ if (variableDeclarations) >+ return parseRemainder(WTFMove(*variableDeclarations)); >+ >+ auto effectfulExpression = parseEffectfulExpression(); >+ if (!effectfulExpression) >+ return Unexpected<Error>(effectfulExpression.error()); >+ >+ return parseRemainder(WTFMove(*effectfulExpression)); >+} >+ >+auto Parser::parseWhileLoop() -> Expected<AST::WhileLoop, Error> { >+ auto origin = consumeType(Lexer::Token::Type::While); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto conditional = parseExpression(); >+ if (!conditional) >+ return Unexpected<Error>(conditional.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ auto body = parseStatement(); >+ if (!body) >+ return Unexpected<Error>(body.error()); >+ >+ return AST::WhileLoop(WTFMove(*origin), WTFMove(*conditional), WTFMove(*body)); >+} >+ >+auto Parser::parseDoWhileLoop() -> Expected<AST::DoWhileLoop, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Do); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto body = parseStatement(); >+ if (!body) >+ return Unexpected<Error>(body.error()); >+ >+ auto whileKeyword = consumeType(Lexer::Token::Type::While); >+ if (!whileKeyword) >+ return Unexpected<Error>(whileKeyword.error()); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto conditional = parseExpression(); >+ if (!conditional) >+ return Unexpected<Error>(conditional.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return AST::DoWhileLoop(WTFMove(*origin), WTFMove(*body), WTFMove(*conditional)); >+} >+ >+auto Parser::parseVariableDeclaration(UniqueRef<AST::UnnamedType>&& type) -> Expected<AST::VariableDeclaration, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto qualifiers = parseQualifiers(); >+ >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ >+ if (tryType(Lexer::Token::Type::Colon)) { >+ auto semantic = parseSemantic(); >+ if (!semantic) >+ return Unexpected<Error>(semantic.error()); >+ >+ if (tryType(Lexer::Token::Type::EqualsSign)) { >+ auto initializer = parseExpression(); >+ if (!initializer) >+ return Unexpected<Error>(initializer.error()); >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), { WTFMove(type) }, name->stringView.toString(), WTFMove(*semantic), WTFMove(*initializer)); >+ } >+ >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), { WTFMove(type) }, name->stringView.toString(), WTFMove(*semantic), WTF::nullopt); >+ } >+ >+ if (tryType(Lexer::Token::Type::EqualsSign)) { >+ auto initializer = parseExpression(); >+ if (!initializer) >+ return Unexpected<Error>(initializer.error()); >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), { WTFMove(type) }, name->stringView.toString(), WTF::nullopt, WTFMove(*initializer)); >+ } >+ >+ return AST::VariableDeclaration(WTFMove(*origin), WTFMove(qualifiers), { WTFMove(type) }, name->stringView.toString(), WTF::nullopt, WTF::nullopt); >+} >+ >+auto Parser::parseVariableDeclarations() -> Expected<AST::VariableDeclarationsStatement, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto type = parseType(); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ auto firstVariableDeclaration = parseVariableDeclaration((*type)->clone()); >+ if (!firstVariableDeclaration) >+ return Unexpected<Error>(firstVariableDeclaration.error()); >+ >+ Vector<AST::VariableDeclaration> result; >+ result.append(WTFMove(*firstVariableDeclaration)); >+ >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto variableDeclaration = parseVariableDeclaration((*type)->clone()); >+ if (!variableDeclaration) >+ return Unexpected<Error>(variableDeclaration.error()); >+ result.append(WTFMove(*variableDeclaration)); >+ } >+ >+ return AST::VariableDeclarationsStatement(WTFMove(*origin), WTFMove(result)); >+} >+ >+auto Parser::parseStatement() -> Expected<UniqueRef<AST::Statement>, Error> { >+ { >+ auto block = backtrackingScope<Expected<AST::Block, Error>>([&]() { >+ return parseBlock(); >+ }); >+ if (block) >+ return { makeUniqueRef<AST::Block>(WTFMove(*block)) }; >+ } >+ >+ { >+ auto ifStatement = backtrackingScope<Expected<AST::IfStatement, Error>>([&]() { >+ return parseIfStatement(); >+ }); >+ if (ifStatement) >+ return { makeUniqueRef<AST::IfStatement>(WTFMove(*ifStatement)) }; >+ } >+ >+ { >+ auto switchStatement = backtrackingScope<Expected<AST::SwitchStatement, Error>>([&]() { >+ return parseSwitchStatement(); >+ }); >+ if (switchStatement) >+ return { makeUniqueRef<AST::SwitchStatement>(WTFMove(*switchStatement)) }; >+ } >+ >+ { >+ auto forLoop = backtrackingScope<Expected<AST::ForLoop, Error>>([&]() { >+ return parseForLoop(); >+ }); >+ if (forLoop) >+ return { makeUniqueRef<AST::ForLoop>(WTFMove(*forLoop)) }; >+ } >+ >+ { >+ auto whileLoop = backtrackingScope<Expected<AST::WhileLoop, Error>>([&]() { >+ return parseWhileLoop(); >+ }); >+ if (whileLoop) >+ return { makeUniqueRef<AST::WhileLoop>(WTFMove(*whileLoop)) }; >+ } >+ >+ { >+ auto doWhileLoop = backtrackingScope<Expected<AST::DoWhileLoop, Error>>([&]() -> Expected<AST::DoWhileLoop, Error> { >+ auto result = parseDoWhileLoop(); >+ if (!result) >+ return Unexpected<Error>(result.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return result; >+ }); >+ if (doWhileLoop) >+ return { makeUniqueRef<AST::DoWhileLoop>(WTFMove(*doWhileLoop)) }; >+ } >+ >+ { >+ auto breakObject = backtrackingScope<Expected<AST::Break, Error>>([&]() -> Expected<AST::Break, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Break); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::Break(WTFMove(*origin)); >+ }); >+ if (breakObject) >+ return { makeUniqueRef<AST::Break>(WTFMove(*breakObject)) }; >+ } >+ >+ { >+ auto continueObject = backtrackingScope<Expected<AST::Continue, Error>>([&]() -> Expected<AST::Continue, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Continue); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::Continue(WTFMove(*origin)); >+ }); >+ if (continueObject) >+ return { makeUniqueRef<AST::Continue>(WTFMove(*continueObject)) }; >+ } >+ >+ { >+ auto fallthroughObject = backtrackingScope<Expected<AST::Fallthrough, Error>>([&]() -> Expected<AST::Fallthrough, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Fallthrough); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::Fallthrough(WTFMove(*origin)); >+ }); >+ if (fallthroughObject) >+ return { makeUniqueRef<AST::Fallthrough>(WTFMove(*fallthroughObject)) }; >+ } >+ >+ { >+ auto trapObject = backtrackingScope<Expected<AST::Trap, Error>>([&]() -> Expected<AST::Trap, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Trap); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::Trap(WTFMove(*origin)); >+ }); >+ if (trapObject) >+ return { makeUniqueRef<AST::Trap>(WTFMove(*trapObject)) }; >+ } >+ >+ { >+ auto returnObject = backtrackingScope<Expected<AST::Return, Error>>([&]() -> Expected<AST::Return, Error> { >+ auto origin = consumeType(Lexer::Token::Type::Return); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ if (auto semicolon = tryType(Lexer::Token::Type::Semicolon)) >+ return AST::Return(WTFMove(*origin), WTF::nullopt); >+ >+ auto expression = parseExpression(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return AST::Return(WTFMove(*origin), { WTFMove(*expression) }); >+ }); >+ if (returnObject) >+ return { makeUniqueRef<AST::Return>(WTFMove(*returnObject)) }; >+ } >+ >+ { >+ auto variableDeclarations = backtrackingScope<Expected<AST::VariableDeclarationsStatement, Error>>([&]() -> Expected<AST::VariableDeclarationsStatement, Error> { >+ auto result = parseVariableDeclarations(); >+ if (!result) >+ return Unexpected<Error>(result.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return result; >+ }); >+ if (variableDeclarations) >+ return { makeUniqueRef<AST::VariableDeclarationsStatement>(WTFMove(*variableDeclarations)) }; >+ } >+ >+ auto effectfulExpression = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto result = parseEffectfulExpression(); >+ if (!result) >+ return Unexpected<Error>(result.error()); >+ >+ auto semicolon = consumeType(Lexer::Token::Type::Semicolon); >+ if (!semicolon) >+ return Unexpected<Error>(semicolon.error()); >+ >+ return result; >+ }); >+ if (effectfulExpression) >+ return { makeUniqueRef<AST::EffectfulExpressionStatement>(WTFMove(*effectfulExpression)) }; >+ >+ return Unexpected<Error>(effectfulExpression.error()); >+} >+ >+auto Parser::parseEffectfulExpression() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ Vector<UniqueRef<AST::Expression>> expressions; >+ >+ auto first = backtrackingScope<Optional<UniqueRef<AST::Expression>>>([&]() -> Optional<UniqueRef<AST::Expression>> { >+ auto effectfulExpression = parseEffectfulAssignment(); >+ if (!effectfulExpression) >+ return WTF::nullopt; >+ return { WTFMove(*effectfulExpression) }; >+ }); >+ if (!first) >+ return { makeUniqueRef<AST::CommaExpression>(WTFMove(*origin), WTFMove(expressions)) }; >+ >+ expressions.append(WTFMove(*first)); >+ >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto expression = parseEffectfulAssignment(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ expressions.append(WTFMove(*expression)); >+ } >+ >+ if (expressions.size() == 1) >+ return WTFMove(expressions[0]); >+ return { makeUniqueRef<AST::CommaExpression>(WTFMove(*origin), WTFMove(expressions)) }; >+} >+ >+auto Parser::parseEffectfulAssignment() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto assignment = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseAssignment(); >+ }); >+ if (assignment) >+ return assignment; >+ >+ assignment = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseEffectfulPrefix(); >+ }); >+ if (assignment) >+ return assignment; >+ >+ assignment = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseCallExpression(); >+ }); >+ if (assignment) >+ return assignment; >+ >+ return Unexpected<Error>(assignment.error()); >+} >+ >+auto Parser::parseEffectfulPrefix() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto prefix = consumeTypes({ Lexer::Token::Type::PlusPlus, Lexer::Token::Type::MinusMinus }); >+ if (!prefix) >+ return Unexpected<Error>(prefix.error()); >+ >+ auto previous = parsePossiblePrefix(); >+ if (!previous) >+ return Unexpected<Error>(previous.error()); >+ >+ switch (prefix->type) { >+ case Lexer::Token::Type::PlusPlus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*prefix), WTFMove(*previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*prefix), "operator++"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->newVariableReference()); >+ return { WTFMove(result) }; >+ } >+ case Lexer::Token::Type::MinusMinus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*prefix), WTFMove(*previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*prefix), "operator--"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->newVariableReference()); >+ return { WTFMove(result) }; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ >+auto Parser::parseEffectfulSuffix() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto effectfulSuffix = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto previous = parsePossibleSuffix(); >+ if (!previous) >+ return Unexpected<Error>(previous.error()); >+ >+ auto suffix = consumeTypes({ Lexer::Token::Type::PlusPlus, Lexer::Token::Type::MinusMinus }); >+ if (!suffix) >+ return Unexpected<Error>(suffix.error()); >+ >+ switch (suffix->type) { >+ case Lexer::Token::Type::PlusPlus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*suffix), WTFMove(*previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*suffix), "operator++"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->oldVariableReference()); >+ return makeUniqueRef<AST::Expression>(WTFMove(result)); >+ } >+ case Lexer::Token::Type::MinusMinus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*suffix), WTFMove(*previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*suffix), "operator--"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->oldVariableReference()); >+ return makeUniqueRef<AST::Expression>(WTFMove(result)); >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ }); >+ if (effectfulSuffix) >+ return effectfulSuffix; >+ >+ effectfulSuffix = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseCallExpression(); >+ }); >+ if (effectfulSuffix) >+ return effectfulSuffix; >+ >+ effectfulSuffix = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ auto expression = parseExpression(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return { WTFMove(*expression) }; >+ }); >+ if (effectfulSuffix) >+ return effectfulSuffix; >+ >+ return Unexpected<Error>(effectfulSuffix.error()); >+} >+ >+auto Parser::parseLimitedSuffixOperator(UniqueRef<AST::Expression>&& previous) -> SuffixExpression >+{ >+ auto type = consumeTypes({ Lexer::Token::Type::FullStop, Lexer::Token::Type::Arrow, Lexer::Token::Type::LeftSquareBracket }); >+ if (!type) >+ return SuffixExpression(WTFMove(previous), false); >+ >+ switch (type->type) { >+ case Lexer::Token::Type::FullStop: { >+ auto identifier = consumeType(Lexer::Token::Type::Identifier); >+ if (!identifier) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::DotExpression>(WTFMove(*type), WTFMove(previous), identifier->stringView.toString()), true); >+ } >+ case Lexer::Token::Type::Arrow: { >+ auto identifier = consumeType(Lexer::Token::Type::Identifier); >+ if (!identifier) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::DotExpression>(Lexer::Token(*type), makeUniqueRef<AST::DereferenceExpression>(WTFMove(*type), WTFMove(previous)), identifier->stringView.toString()), true); >+ } >+ case Lexer::Token::Type::LeftSquareBracket: { >+ auto expression = parseExpression(); >+ if (!expression) >+ return SuffixExpression(WTFMove(previous), false); >+ if (!consumeType(Lexer::Token::Type::RightSquareBracket)) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::IndexExpression>(WTFMove(*type), WTFMove(previous), WTFMove(*expression)), true); >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return SuffixExpression(WTFMove(previous), false); >+ } >+} >+ >+auto Parser::parseSuffixOperator(UniqueRef<AST::Expression>&& previous) -> SuffixExpression >+{ >+ auto suffix = consumeTypes({ Lexer::Token::Type::FullStop, Lexer::Token::Type::Arrow, Lexer::Token::Type::LeftSquareBracket, Lexer::Token::Type::PlusPlus, Lexer::Token::Type::MinusMinus }); >+ if (!suffix) >+ return SuffixExpression(WTFMove(previous), false); >+ >+ switch (suffix->type) { >+ case Lexer::Token::Type::FullStop: { >+ auto identifier = consumeType(Lexer::Token::Type::Identifier); >+ if (!identifier) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::DotExpression>(WTFMove(*suffix), WTFMove(previous), identifier->stringView.toString()), true); >+ } >+ case Lexer::Token::Type::Arrow: { >+ auto identifier = consumeType(Lexer::Token::Type::Identifier); >+ if (!identifier) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::DotExpression>(Lexer::Token(*suffix), makeUniqueRef<AST::DereferenceExpression>(WTFMove(*suffix), WTFMove(previous)), identifier->stringView.toString()), true); >+ } >+ case Lexer::Token::Type::LeftSquareBracket: { >+ auto expression = parseExpression(); >+ if (!expression) >+ return SuffixExpression(WTFMove(previous), false); >+ if (!consumeType(Lexer::Token::Type::RightSquareBracket)) >+ return SuffixExpression(WTFMove(previous), false); >+ return SuffixExpression(makeUniqueRef<AST::IndexExpression>(WTFMove(*suffix), WTFMove(previous), WTFMove(*expression)), true); >+ } >+ case Lexer::Token::Type::PlusPlus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*suffix), WTFMove(previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*suffix), "operator++"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->oldVariableReference()); >+ return SuffixExpression(WTFMove(result), true); >+ } >+ case Lexer::Token::Type::MinusMinus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*suffix), WTFMove(previous)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*suffix), "operator--"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->oldVariableReference()); >+ return SuffixExpression(WTFMove(result), true); >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return SuffixExpression(WTFMove(previous), false); >+ } >+} >+ >+auto Parser::parseExpression() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto first = parsePossibleTernaryConditional(); >+ if (!first) >+ return Unexpected<Error>(first.error()); >+ >+ Vector<UniqueRef<AST::Expression>> expressions; >+ expressions.append(WTFMove(*first)); >+ >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto expression = parsePossibleTernaryConditional(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ expressions.append(WTFMove(*expression)); >+ } >+ >+ if (expressions.size() == 1) >+ return WTFMove(expressions[0]); >+ return { makeUniqueRef<AST::CommaExpression>(WTFMove(*origin), WTFMove(expressions)) }; >+} >+ >+auto Parser::parseTernaryConditional() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto predicate = parsePossibleLogicalBinaryOperation(); >+ if (!predicate) >+ return Unexpected<Error>(predicate.error()); >+ >+ auto questionMark = consumeType(Lexer::Token::Type::QuestionMark); >+ if (!questionMark) >+ return Unexpected<Error>(questionMark.error()); >+ >+ auto bodyExpression = parseExpression(); >+ if (!bodyExpression) >+ return Unexpected<Error>(bodyExpression.error()); >+ >+ auto colon = consumeType(Lexer::Token::Type::Colon); >+ if (!colon) >+ return Unexpected<Error>(colon.error()); >+ >+ auto elseExpression = parsePossibleTernaryConditional(); >+ if (!elseExpression) >+ return Unexpected<Error>(elseExpression.error()); >+ >+ Vector<UniqueRef<AST::Expression>> castArguments; >+ castArguments.append(WTFMove(*predicate)); >+ auto boolCast = makeUniqueRef<AST::CallExpression>(Lexer::Token(*origin), "bool"_str, WTFMove(castArguments)); >+ return { makeUniqueRef<AST::TernaryExpression>(WTFMove(*origin), WTFMove(boolCast), WTFMove(*bodyExpression), WTFMove(*elseExpression)) }; >+} >+ >+auto Parser::parseAssignment() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto origin = peek(); >+ if (!origin) >+ return Unexpected<Error>(origin.error()); >+ >+ auto left = parsePossiblePrefix(); >+ if (!left) >+ return Unexpected<Error>(left.error()); >+ >+ auto assignmentOperator = consumeTypes({ >+ Lexer::Token::Type::EqualsSign, >+ Lexer::Token::Type::PlusEquals, >+ Lexer::Token::Type::MinusEquals, >+ Lexer::Token::Type::TimesEquals, >+ Lexer::Token::Type::DivideEquals, >+ Lexer::Token::Type::ModEquals, >+ Lexer::Token::Type::XorEquals, >+ Lexer::Token::Type::AndEquals, >+ Lexer::Token::Type::OrEquals, >+ Lexer::Token::Type::RightShiftEquals, >+ Lexer::Token::Type::LeftShiftEquals >+ }); >+ if (!assignmentOperator) >+ return Unexpected<Error>(assignmentOperator.error()); >+ >+ auto right = parsePossibleTernaryConditional(); >+ if (!right) >+ return Unexpected<Error>(right.error()); >+ >+ if (assignmentOperator->type == Lexer::Token::Type::EqualsSign) >+ return { makeUniqueRef<AST::AssignmentExpression>(WTFMove(*origin), WTFMove(*left), WTFMove(*right))}; >+ >+ String name; >+ switch (assignmentOperator->type) { >+ case Lexer::Token::Type::PlusEquals: >+ name = "operator+"_str; >+ break; >+ case Lexer::Token::Type::MinusEquals: >+ name = "operator-"_str; >+ break; >+ case Lexer::Token::Type::TimesEquals: >+ name = "operator*"_str; >+ break; >+ case Lexer::Token::Type::DivideEquals: >+ name = "operator/"_str; >+ break; >+ case Lexer::Token::Type::ModEquals: >+ name = "operator%"_str; >+ break; >+ case Lexer::Token::Type::XorEquals: >+ name = "operator^"_str; >+ break; >+ case Lexer::Token::Type::AndEquals: >+ name = "operator&"_str; >+ break; >+ case Lexer::Token::Type::OrEquals: >+ name = "operator|"_str; >+ break; >+ case Lexer::Token::Type::RightShiftEquals: >+ name = "operator>>"_str; >+ break; >+ case Lexer::Token::Type::LeftShiftEquals: >+ name = "operator<<"_str; >+ break; >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*origin), WTFMove(*left)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ callArguments.append(WTFMove(*right)); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(WTFMove(*origin), WTFMove(name), WTFMove(callArguments))); >+ result->setResultExpression(result->newVariableReference()); >+ return { WTFMove(result) }; >+} >+ >+auto Parser::parsePossibleTernaryConditional() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto ternaryExpression = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseTernaryConditional(); >+ }); >+ if (ternaryExpression) >+ return ternaryExpression; >+ >+ auto assignmentExpression = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parseAssignment(); >+ }); >+ if (assignmentExpression) >+ return assignmentExpression; >+ >+ auto binaryOperation = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() { >+ return parsePossibleLogicalBinaryOperation(); >+ }); >+ if (binaryOperation) >+ return binaryOperation; >+ >+ return Unexpected<Error>(binaryOperation.error()); >+} >+ >+auto Parser::parsePossibleLogicalBinaryOperation() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto parsedPrevious = parsePossibleRelationalBinaryOperation(); >+ if (!parsedPrevious) >+ return Unexpected<Error>(parsedPrevious.error()); >+ UniqueRef<AST::Expression> previous = WTFMove(*parsedPrevious); >+ >+ while (auto logicalBinaryOperation = tryTypes({ >+ Lexer::Token::Type::OrOr, >+ Lexer::Token::Type::AndAnd, >+ Lexer::Token::Type::Or, >+ Lexer::Token::Type::Xor, >+ Lexer::Token::Type::And >+ })) { >+ auto next = parsePossibleRelationalBinaryOperation(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (logicalBinaryOperation->type) { >+ case Lexer::Token::Type::OrOr: >+ previous = makeUniqueRef<AST::LogicalExpression>(WTFMove(*logicalBinaryOperation), AST::LogicalExpression::Type::Or, WTFMove(previous), WTFMove(*next)); >+ break; >+ case Lexer::Token::Type::AndAnd: >+ previous = makeUniqueRef<AST::LogicalExpression>(WTFMove(*logicalBinaryOperation), AST::LogicalExpression::Type::And, WTFMove(previous), WTFMove(*next)); >+ break; >+ case Lexer::Token::Type::Or: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*logicalBinaryOperation), "operator|"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::Xor: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*logicalBinaryOperation), "operator^"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::And: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*logicalBinaryOperation), "operator&"_str, WTFMove(callArguments)); >+ break; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return { WTFMove(previous) }; >+} >+ >+auto Parser::parsePossibleRelationalBinaryOperation() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto parsedPrevious = parsePossibleShift(); >+ if (!parsedPrevious) >+ return Unexpected<Error>(parsedPrevious.error()); >+ UniqueRef<AST::Expression> previous = WTFMove(*parsedPrevious); >+ >+ while (auto relationalBinaryOperation = tryTypes({ >+ Lexer::Token::Type::LessThanSign, >+ Lexer::Token::Type::GreaterThanSign, >+ Lexer::Token::Type::LessThanOrEqualTo, >+ Lexer::Token::Type::GreaterThanOrEqualTo, >+ Lexer::Token::Type::EqualComparison, >+ Lexer::Token::Type::NotEqual >+ })) { >+ auto next = parsePossibleShift(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (relationalBinaryOperation->type) { >+ case Lexer::Token::Type::LessThanSign: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*relationalBinaryOperation), "operator<"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::GreaterThanSign: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*relationalBinaryOperation), "operator>"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::LessThanOrEqualTo: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*relationalBinaryOperation), "operator<="_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::GreaterThanOrEqualTo: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*relationalBinaryOperation), "operator>="_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::EqualComparison: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*relationalBinaryOperation), "operator=="_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::NotEqual: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(Lexer::Token(*relationalBinaryOperation), "operator=="_str, WTFMove(callArguments)); >+ previous = makeUniqueRef<AST::LogicalNotExpression>(WTFMove(*relationalBinaryOperation), WTFMove(previous)); >+ break; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return WTFMove(previous); >+} >+ >+auto Parser::parsePossibleShift() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto parsedPrevious = parsePossibleAdd(); >+ if (!parsedPrevious) >+ return Unexpected<Error>(parsedPrevious.error()); >+ UniqueRef<AST::Expression> previous = WTFMove(*parsedPrevious); >+ >+ while (auto shift = tryTypes({ >+ Lexer::Token::Type::LeftShift, >+ Lexer::Token::Type::RightShift >+ })) { >+ auto next = parsePossibleAdd(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (shift->type) { >+ case Lexer::Token::Type::LeftShift: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*shift), "operator<<"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::RightShift: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*shift), "operator>>"_str, WTFMove(callArguments)); >+ break; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return WTFMove(previous); >+} >+ >+auto Parser::parsePossibleAdd() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto parsedPrevious = parsePossibleMultiply(); >+ if (!parsedPrevious) >+ return Unexpected<Error>(parsedPrevious.error()); >+ UniqueRef<AST::Expression> previous = WTFMove(*parsedPrevious); >+ >+ while (auto add = tryTypes({ >+ Lexer::Token::Type::Plus, >+ Lexer::Token::Type::Minus >+ })) { >+ auto next = parsePossibleMultiply(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (add->type) { >+ case Lexer::Token::Type::Plus: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*add), "operator+"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::Minus: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*add), "operator-"_str, WTFMove(callArguments)); >+ break; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return WTFMove(previous); >+} >+ >+auto Parser::parsePossibleMultiply() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto parsedPrevious = parsePossiblePrefix(); >+ if (!parsedPrevious) >+ return Unexpected<Error>(parsedPrevious.error()); >+ UniqueRef<AST::Expression> previous = WTFMove(*parsedPrevious); >+ >+ while (auto multiply = tryTypes({ >+ Lexer::Token::Type::Star, >+ Lexer::Token::Type::Divide, >+ Lexer::Token::Type::Mod >+ })) { >+ auto next = parsePossiblePrefix(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (multiply->type) { >+ case Lexer::Token::Type::Star: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*multiply), "operator*"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::Divide: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*multiply), "operator/"_str, WTFMove(callArguments)); >+ break; >+ } >+ case Lexer::Token::Type::Mod: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(previous)); >+ callArguments.append(WTFMove(*next)); >+ previous = makeUniqueRef<AST::CallExpression>(WTFMove(*multiply), "operator%"_str, WTFMove(callArguments)); >+ break; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return WTFMove(previous); >+} >+ >+auto Parser::parsePossiblePrefix() -> Expected<UniqueRef<AST::Expression>, Error> { >+ if (auto prefix = tryTypes({ >+ Lexer::Token::Type::PlusPlus, >+ Lexer::Token::Type::MinusMinus, >+ Lexer::Token::Type::Plus, >+ Lexer::Token::Type::Minus, >+ Lexer::Token::Type::Tilde, >+ Lexer::Token::Type::ExclamationPoint, >+ Lexer::Token::Type::And, >+ Lexer::Token::Type::At, >+ Lexer::Token::Type::Star >+ })) { >+ auto next = parsePossiblePrefix(); >+ if (!next) >+ return Unexpected<Error>(next.error()); >+ >+ switch (prefix->type) { >+ case Lexer::Token::Type::PlusPlus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*prefix), WTFMove(*next)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "operator++"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->newVariableReference()); >+ return { WTFMove(result) }; >+ } >+ case Lexer::Token::Type::MinusMinus: { >+ auto result = AST::ReadModifyWriteExpression::create(Lexer::Token(*prefix), WTFMove(*next)); >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(result->oldVariableReference()); >+ result->setNewValueExpression(makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "operator--"_str, WTFMove(callArguments))); >+ result->setResultExpression(result->newVariableReference()); >+ return { WTFMove(result) }; >+ } >+ case Lexer::Token::Type::Plus: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(*next)); >+ return { makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "operator+"_str, WTFMove(callArguments)) }; >+ } >+ case Lexer::Token::Type::Minus: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(*next)); >+ return { makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "operator-"_str, WTFMove(callArguments)) }; >+ } >+ case Lexer::Token::Type::Tilde: { >+ Vector<UniqueRef<AST::Expression>> callArguments; >+ callArguments.append(WTFMove(*next)); >+ return { makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "operator~"_str, WTFMove(callArguments)) }; >+ } >+ case Lexer::Token::Type::ExclamationPoint: { >+ Vector<UniqueRef<AST::Expression>> castArguments; >+ castArguments.append(WTFMove(*next)); >+ auto boolCast = makeUniqueRef<AST::CallExpression>(Lexer::Token(*prefix), "bool"_str, WTFMove(castArguments)); >+ return { makeUniqueRef<AST::LogicalNotExpression>(Lexer::Token(*prefix), WTFMove(boolCast)) }; >+ } >+ case Lexer::Token::Type::And: >+ return { makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(*prefix), WTFMove(*next)) }; >+ case Lexer::Token::Type::At: >+ return { makeUniqueRef<AST::MakeArrayReferenceExpression>(Lexer::Token(*prefix), WTFMove(*next)) }; >+ case Lexer::Token::Type::Star: >+ return { makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(*prefix), WTFMove(*next)) }; >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+ } >+ >+ return parsePossibleSuffix(); >+} >+ >+auto Parser::parsePossibleSuffix() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto suffix = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto expression = parseCallExpression(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ >+ while (true) { >+ auto result = backtrackingScope<SuffixExpression>([&]() -> SuffixExpression { >+ return parseLimitedSuffixOperator(WTFMove(*expression)); >+ }); >+ expression = WTFMove(result.result); >+ if (!result) >+ break; >+ } >+ return expression; >+ }); >+ if (suffix) >+ return suffix; >+ >+ suffix = backtrackingScope<Expected<UniqueRef<AST::Expression>, Error>>([&]() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto expression = parseTerm(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ >+ while (true) { >+ auto result = backtrackingScope<SuffixExpression>([&]() -> SuffixExpression { >+ return parseSuffixOperator(WTFMove(*expression)); >+ }); >+ expression = WTFMove(result.result); >+ if (!result) >+ break; >+ } >+ return expression; >+ }); >+ if (suffix) >+ return suffix; >+ >+ return Unexpected<Error>(suffix.error()); >+} >+ >+auto Parser::parseCallExpression() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto name = consumeType(Lexer::Token::Type::Identifier); >+ if (!name) >+ return Unexpected<Error>(name.error()); >+ auto callName = name->stringView.toString(); >+ >+ auto leftParenthesis = consumeType(Lexer::Token::Type::LeftParenthesis); >+ if (!leftParenthesis) >+ return Unexpected<Error>(leftParenthesis.error()); >+ >+ Vector<UniqueRef<AST::Expression>> arguments; >+ if (tryType(Lexer::Token::Type::RightParenthesis)) >+ return { makeUniqueRef<AST::CallExpression>(WTFMove(*name), WTFMove(callName), WTFMove(arguments)) }; >+ >+ auto firstArgument = parsePossibleTernaryConditional(); >+ if (!firstArgument) >+ return Unexpected<Error>(firstArgument.error()); >+ arguments.append(WTFMove(*firstArgument)); >+ while (tryType(Lexer::Token::Type::Comma)) { >+ auto argument = parsePossibleTernaryConditional(); >+ if (!argument) >+ return Unexpected<Error>(argument.error()); >+ arguments.append(WTFMove(*argument)); >+ } >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return { makeUniqueRef<AST::CallExpression>(WTFMove(*name), WTFMove(callName), WTFMove(arguments)) }; >+} >+ >+auto Parser::parseTerm() -> Expected<UniqueRef<AST::Expression>, Error> { >+ auto type = consumeTypes({ >+ Lexer::Token::Type::IntLiteral, >+ Lexer::Token::Type::UintLiteral, >+ Lexer::Token::Type::FloatLiteral, >+ Lexer::Token::Type::Null, >+ Lexer::Token::Type::True, >+ Lexer::Token::Type::False, >+ Lexer::Token::Type::Identifier, >+ Lexer::Token::Type::LeftParenthesis >+ }); >+ if (!type) >+ return Unexpected<Error>(type.error()); >+ >+ switch (type->type) { >+ case Lexer::Token::Type::IntLiteral: { >+ auto value = intLiteralToInt(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return { makeUniqueRef<AST::IntegerLiteral>(WTFMove(*type), *value) }; >+ } >+ case Lexer::Token::Type::UintLiteral: { >+ auto value = uintLiteralToUint(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return { makeUniqueRef<AST::UnsignedIntegerLiteral>(WTFMove(*type), *value) }; >+ } >+ case Lexer::Token::Type::FloatLiteral: { >+ auto value = floatLiteralToFloat(type->stringView); >+ if (!value) >+ return Unexpected<Error>(value.error()); >+ return { makeUniqueRef<AST::FloatLiteral>(WTFMove(*type), *value) }; >+ } >+ case Lexer::Token::Type::Null: >+ return { makeUniqueRef<AST::NullLiteral>(WTFMove(*type)) }; >+ case Lexer::Token::Type::True: >+ return { makeUniqueRef<AST::BooleanLiteral>(WTFMove(*type), true) }; >+ case Lexer::Token::Type::False: >+ return { makeUniqueRef<AST::BooleanLiteral>(WTFMove(*type), false) }; >+ case Lexer::Token::Type::Identifier: { >+ auto name = type->stringView.toString(); >+ return { makeUniqueRef<AST::VariableReference>(WTFMove(*type), WTFMove(name)) }; >+ } >+ case Lexer::Token::Type::LeftParenthesis: { >+ auto expression = parseExpression(); >+ if (!expression) >+ return Unexpected<Error>(expression.error()); >+ >+ auto rightParenthesis = consumeType(Lexer::Token::Type::RightParenthesis); >+ if (!rightParenthesis) >+ return Unexpected<Error>(rightParenthesis.error()); >+ >+ return { WTFMove(*expression) }; >+ } >+ default: >+ ASSERT_NOT_REACHED(); >+ return Unexpected<Error>(Error("Something really bad happened"_str)); >+ } >+} >+ > } > > } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.h >index 3cf66ced220f632a97c3a41e9d895fd5f12baf3c..8da7b2ab48965993ba4e3de22c95b19ff28820a6 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.h >@@ -103,7 +103,131 @@ namespace WebCore { > namespace WHLSL { > > class Parser { >+public: >+ enum class Mode { >+ StandardLibrary, >+ User >+ }; > >+ struct Error { >+ Error(String&& error) >+ : error(WTFMove(error)) >+ { >+ } >+ >+ String error; >+ }; >+ >+ Parser(); >+ >+ Optional<Error> parse(Program&, StringView, Mode); >+ >+private: >+ template<typename T> T backtrackingScope(std::function<T()> callback) >+ { >+ auto state = m_lexer.state(); >+ auto result = callback(); >+ if (result) >+ return result; >+ m_lexer.setState(WTFMove(state)); >+ return result; >+ } >+ >+ Unexpected<Error> fail(const String& message); >+ Expected<Lexer::Token, Error> peek(); >+ Optional<Lexer::Token> tryType(Lexer::Token::Type); >+ Optional<Lexer::Token> tryTypes(Vector<Lexer::Token::Type>); >+ Expected<Lexer::Token, Error> consumeType(Lexer::Token::Type); >+ Expected<Lexer::Token, Error> consumeTypes(Vector<Lexer::Token::Type>); >+ >+ Expected<Variant<int, unsigned>, Error> consumeIntegralLiteral(); >+ Expected<unsigned, Error> consumeNonNegativeIntegralLiteral(); >+ Expected<AST::ConstantExpression, Error> parseConstantExpression(); >+ Expected<AST::TypeArgument, Error> parseTypeArgument(); >+ Expected<AST::TypeArguments, Error> parseTypeArguments(); >+ struct TypeSuffixAbbreviated { >+ Lexer::Token token; >+ Optional<unsigned> numElements; >+ }; >+ Expected<TypeSuffixAbbreviated, Error> parseTypeSuffixAbbreviated(); >+ struct TypeSuffixNonAbbreviated { >+ Lexer::Token token; >+ Optional<AST::ReferenceType::AddressSpace> addressSpace; >+ Optional<unsigned> numElements; >+ }; >+ Expected<TypeSuffixNonAbbreviated, Error> parseTypeSuffixNonAbbreviated(); >+ Expected<UniqueRef<AST::UnnamedType>, Error> parseAddressSpaceType(); >+ Expected<UniqueRef<AST::UnnamedType>, Error> parseNonAddressSpaceType(); >+ Expected<UniqueRef<AST::UnnamedType>, Error> parseType(); >+ Expected<AST::TypeDefinition, Error> parseTypeDefinition(); >+ Expected<AST::BuiltInSemantic, Error> parseBuiltInSemantic(); >+ Expected<AST::ResourceSemantic, Error> parseResourceSemantic(); >+ Expected<AST::SpecializationConstantSemantic, Error> parseSpecializationConstantSemantic(); >+ Expected<AST::StageInOutSemantic, Error> parseStageInOutSemantic(); >+ Expected<AST::Semantic, Error> parseSemantic(); >+ AST::Qualifiers parseQualifiers(); >+ Expected<AST::StructureElement, Error> parseStructureElement(); >+ Expected<AST::StructureDefinition, Error> parseStructureDefinition(); >+ Expected<AST::EnumerationDefinition, Error> parseEnumerationDefinition(); >+ Expected<AST::EnumerationMember, Error> parseEnumerationMember(); >+ Expected<AST::NativeTypeDeclaration, Error> parseNativeTypeDeclaration(); >+ Expected<AST::NumThreadsFunctionAttribute, Error> parseNumThreadsFunctionAttribute(); >+ Expected<AST::AttributeBlock, Error> parseAttributeBlock(); >+ Expected<AST::VariableDeclaration, Error> parseParameter(); >+ Expected<AST::VariableDeclarations, Error> parseParameters(); >+ Expected<AST::FunctionDeclaration, Error> parseEntryPointFunctionDeclaration(); >+ Expected<AST::FunctionDeclaration, Error> parseRegularFunctionDeclaration(); >+ Expected<AST::FunctionDeclaration, Error> parseOperatorFunctionDeclaration(); >+ Expected<AST::FunctionDeclaration, Error> parseFunctionDeclaration(); >+ Expected<AST::FunctionDefinition, Error> parseFunctionDefinition(); >+ Expected<AST::NativeFunctionDeclaration, Error> parseNativeFunctionDeclaration(); >+ >+ Expected<AST::Block, Error> parseBlock(); >+ AST::Block parseBlockBody(Lexer::Token&& origin); >+ Expected<AST::IfStatement, Error> parseIfStatement(); >+ Expected<AST::SwitchStatement, Error> parseSwitchStatement(); >+ Expected<AST::SwitchCase, Error> parseSwitchCase(); >+ Expected<AST::ForLoop, Error> parseForLoop(); >+ Expected<AST::WhileLoop, Error> parseWhileLoop(); >+ Expected<AST::DoWhileLoop, Error> parseDoWhileLoop(); >+ Expected<AST::VariableDeclaration, Error> parseVariableDeclaration(UniqueRef<AST::UnnamedType>&&); >+ Expected<AST::VariableDeclarationsStatement, Error> parseVariableDeclarations(); >+ Expected<UniqueRef<AST::Statement>, Error> parseStatement(); >+ >+ Expected<UniqueRef<AST::Expression>, Error> parseEffectfulExpression(); >+ Expected<UniqueRef<AST::Expression>, Error> parseEffectfulAssignment(); >+ Expected<UniqueRef<AST::Expression>, Error> parseEffectfulPrefix(); >+ Expected<UniqueRef<AST::Expression>, Error> parseEffectfulSuffix(); >+ struct SuffixExpression { >+ SuffixExpression(UniqueRef<AST::Expression>&& result, bool success) >+ : result(WTFMove(result)) >+ , success(success) >+ { >+ } >+ >+ UniqueRef<AST::Expression> result; >+ bool success; >+ operator bool() const { return success; } >+ }; >+ SuffixExpression parseLimitedSuffixOperator(UniqueRef<AST::Expression>&&); >+ SuffixExpression parseSuffixOperator(UniqueRef<AST::Expression>&&); >+ >+ Expected<UniqueRef<AST::Expression>, Error> parseExpression(); >+ Expected<UniqueRef<AST::Expression>, Error> parseTernaryConditional(); >+ Expected<UniqueRef<AST::Expression>, Error> parseAssignment(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleTernaryConditional(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleLogicalBinaryOperation(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleRelationalBinaryOperation(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleShift(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleAdd(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleMultiply(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossiblePrefix(); >+ Expected<UniqueRef<AST::Expression>, Error> parsePossibleSuffix(); >+ Expected<UniqueRef<AST::Expression>, Error> parseCallExpression(); >+ Expected<UniqueRef<AST::Expression>, Error> parseTerm(); >+ >+ Lexer m_lexer; >+ Mode m_mode; > }; > > }
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 192355
:
356468
|
356569
|
356570
|
356585
|
356695
|
356778
|
356863
|
356947
|
357031
|
357035
|
357038
|
357081
|
357103
|
357199
|
357207
|
357225
|
357245
|
357268
|
357277
|
357303
|
357304
|
357361
|
357410
|
357430
|
357458
|
357520
|
357602
|
357749
|
357754
|
357765
|
357869
|
357889
|
357929
|
357932
|
357975
|
358866
|
358880
|
358902
|
359250