Title: [291075] trunk/Source/WebGPU
Revision
291075
Author
[email protected]
Date
2022-03-09 14:25:11 -0800 (Wed, 09 Mar 2022)

Log Message

[WGSL] Implement enough of the Parser for the simplest shaders
https://bugs.webkit.org/show_bug.cgi?id=237629

Reviewed by Myles Maxfield.

The specific "hello-world"-like shaders that I want this to be able to parse are included in WGSLParserTests.mm.

The general approach to the parser, such as its templating by the Lexer, is directly copied from JSC's parser.
Things are a bit simpler for us as WGSL is such a simple language to parse, being strictly LR(1).

In this patch I also deleted BlockAttribute, since this attribute was recently removed from the language.

* WGSL/AST/Attribute.h:
(WGSL::AST::Attribute::isBlock const): Deleted.
* WGSL/AST/Expressions/TypeConversion.h:
* WGSL/AST/FunctionDecl.h:
* WGSL/AST/ShaderModule.h:
* WGSL/AST/Statements/AssignmentStatement.h:
* WGSL/AST/StructureDecl.h:
* WGSL/AST/TypeDecl.h:
(WGSL::AST::ParameterizedType::stringViewToKind):
* WGSL/CompilationMessage.h:
* WGSL/Parser.cpp: Added.
(WGSL::Parser::Parser):
(WGSL::Parser::current):
(WGSL::parse):
(WGSL::parseLChar):
(WGSL::parseUChar):
(WGSL::Parser<Lexer>::consumeType):
(WGSL::Parser<Lexer>::consume):
(WGSL::Parser<Lexer>::parseShader):
(WGSL::Parser<Lexer>::parseGlobalDecl):
(WGSL::Parser<Lexer>::parseAttributes):
(WGSL::Parser<Lexer>::parseAttribute):
(WGSL::Parser<Lexer>::parseStructDecl):
(WGSL::Parser<Lexer>::parseStructMember):
(WGSL::Parser<Lexer>::parseTypeDecl):
(WGSL::Parser<Lexer>::parseTypeDeclAfterIdentifier):
(WGSL::Parser<Lexer>::parseGlobalVariableDecl):
(WGSL::Parser<Lexer>::parseVariableQualifier):
(WGSL::Parser<Lexer>::parseStorageClass):
(WGSL::Parser<Lexer>::parseAccessMode):
(WGSL::Parser<Lexer>::parseFunctionDecl):
(WGSL::Parser<Lexer>::parseParameter):
(WGSL::Parser<Lexer>::parseStatement):
(WGSL::Parser<Lexer>::parseCompoundStatement):
(WGSL::Parser<Lexer>::parseReturnStatement):
(WGSL::Parser<Lexer>::parseShortCircuitOrExpression):
(WGSL::Parser<Lexer>::parseRelationalExpression):
(WGSL::Parser<Lexer>::parseShiftExpression):
(WGSL::Parser<Lexer>::parseAdditiveExpression):
(WGSL::Parser<Lexer>::parseMultiplicativeExpression):
(WGSL::Parser<Lexer>::parseUnaryExpression):
(WGSL::Parser<Lexer>::parseSingularExpression):
(WGSL::Parser<Lexer>::parsePostfixExpression):
(WGSL::Parser<Lexer>::parsePrimaryExpression):
(WGSL::Parser<Lexer>::parseExpression):
(WGSL::Parser<Lexer>::parseLHSExpression):
(WGSL::Parser<Lexer>::parseCoreLHSExpression):
(WGSL::Parser<Lexer>::parseArgumentExpressionList):
* WGSL/Parser.h: Copied from Source/WebGPU/WGSL/CompilationMessage.h.
* WGSL/WGSL.cpp:
(WGSL::staticCheck):
(WGSL::SuccessfulCheck::SuccessfulCheck):
* WGSL/WGSL.h:
* WebGPU.xcodeproj/project.pbxproj:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebGPU/ChangeLog (291074 => 291075)


--- trunk/Source/WebGPU/ChangeLog	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/ChangeLog	2022-03-09 22:25:11 UTC (rev 291075)
@@ -1,3 +1,72 @@
+2022-03-09  Robin Morisset  <[email protected]>
+
+        [WGSL] Implement enough of the Parser for the simplest shaders
+        https://bugs.webkit.org/show_bug.cgi?id=237629
+
+        Reviewed by Myles Maxfield.
+
+        The specific "hello-world"-like shaders that I want this to be able to parse are included in WGSLParserTests.mm.
+
+        The general approach to the parser, such as its templating by the Lexer, is directly copied from JSC's parser.
+        Things are a bit simpler for us as WGSL is such a simple language to parse, being strictly LR(1).
+
+        In this patch I also deleted BlockAttribute, since this attribute was recently removed from the language.
+
+        * WGSL/AST/Attribute.h:
+        (WGSL::AST::Attribute::isBlock const): Deleted.
+        * WGSL/AST/Expressions/TypeConversion.h:
+        * WGSL/AST/FunctionDecl.h:
+        * WGSL/AST/ShaderModule.h:
+        * WGSL/AST/Statements/AssignmentStatement.h:
+        * WGSL/AST/StructureDecl.h:
+        * WGSL/AST/TypeDecl.h:
+        (WGSL::AST::ParameterizedType::stringViewToKind):
+        * WGSL/CompilationMessage.h:
+        * WGSL/Parser.cpp: Added.
+        (WGSL::Parser::Parser):
+        (WGSL::Parser::current):
+        (WGSL::parse):
+        (WGSL::parseLChar):
+        (WGSL::parseUChar):
+        (WGSL::Parser<Lexer>::consumeType):
+        (WGSL::Parser<Lexer>::consume):
+        (WGSL::Parser<Lexer>::parseShader):
+        (WGSL::Parser<Lexer>::parseGlobalDecl):
+        (WGSL::Parser<Lexer>::parseAttributes):
+        (WGSL::Parser<Lexer>::parseAttribute):
+        (WGSL::Parser<Lexer>::parseStructDecl):
+        (WGSL::Parser<Lexer>::parseStructMember):
+        (WGSL::Parser<Lexer>::parseTypeDecl):
+        (WGSL::Parser<Lexer>::parseTypeDeclAfterIdentifier):
+        (WGSL::Parser<Lexer>::parseGlobalVariableDecl):
+        (WGSL::Parser<Lexer>::parseVariableQualifier):
+        (WGSL::Parser<Lexer>::parseStorageClass):
+        (WGSL::Parser<Lexer>::parseAccessMode):
+        (WGSL::Parser<Lexer>::parseFunctionDecl):
+        (WGSL::Parser<Lexer>::parseParameter):
+        (WGSL::Parser<Lexer>::parseStatement):
+        (WGSL::Parser<Lexer>::parseCompoundStatement):
+        (WGSL::Parser<Lexer>::parseReturnStatement):
+        (WGSL::Parser<Lexer>::parseShortCircuitOrExpression):
+        (WGSL::Parser<Lexer>::parseRelationalExpression):
+        (WGSL::Parser<Lexer>::parseShiftExpression):
+        (WGSL::Parser<Lexer>::parseAdditiveExpression):
+        (WGSL::Parser<Lexer>::parseMultiplicativeExpression):
+        (WGSL::Parser<Lexer>::parseUnaryExpression):
+        (WGSL::Parser<Lexer>::parseSingularExpression):
+        (WGSL::Parser<Lexer>::parsePostfixExpression):
+        (WGSL::Parser<Lexer>::parsePrimaryExpression):
+        (WGSL::Parser<Lexer>::parseExpression):
+        (WGSL::Parser<Lexer>::parseLHSExpression):
+        (WGSL::Parser<Lexer>::parseCoreLHSExpression):
+        (WGSL::Parser<Lexer>::parseArgumentExpressionList):
+        * WGSL/Parser.h: Copied from Source/WebGPU/WGSL/CompilationMessage.h.
+        * WGSL/WGSL.cpp:
+        (WGSL::staticCheck):
+        (WGSL::SuccessfulCheck::SuccessfulCheck):
+        * WGSL/WGSL.h:
+        * WebGPU.xcodeproj/project.pbxproj:
+
 2022-03-08  Robin Morisset  <[email protected]>
 
         [WGSL] Add enough of the AST for the simplest shaders

Modified: trunk/Source/WebGPU/WGSL/AST/Attribute.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/Attribute.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/Attribute.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -36,7 +36,6 @@
     WTF_MAKE_FAST_ALLOCATED;
 public:
     enum class Kind {
-        Block,
         Group,
         Binding,
         Stage,
@@ -52,7 +51,6 @@
     virtual ~Attribute() {};
 
     virtual Kind kind() const = 0 ;
-    bool isBlock() const { return kind() == Kind::Block; }
     bool isGroup() const { return kind() == Kind::Group; }
     bool isBinding() const { return kind() == Kind::Binding; }
     bool isStage() const { return kind() == Kind::Stage; }
@@ -60,17 +58,6 @@
     bool isBuiltin() const { return kind() == Kind::Builtin; }
 };
 
-class BlockAttribute final : public Attribute {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    BlockAttribute(SourceSpan span)
-        : Attribute(span)
-    {
-    }
-
-    Kind kind() const override { return Kind::Block; }
-};
-
 class GroupAttribute final : public Attribute {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -166,7 +153,6 @@
     static bool isType(const WGSL::AST::Attribute& attr) { return attr.predicate; } \
 SPECIALIZE_TYPE_TRAITS_END()
 
-SPECIALIZE_TYPE_TRAITS_WGSL_ATTRIBUTE(BlockAttribute, isBlock())
 SPECIALIZE_TYPE_TRAITS_WGSL_ATTRIBUTE(GroupAttribute, isGroup())
 SPECIALIZE_TYPE_TRAITS_WGSL_ATTRIBUTE(BindingAttribute, isBinding())
 SPECIALIZE_TYPE_TRAITS_WGSL_ATTRIBUTE(StageAttribute, isStage())

Modified: trunk/Source/WebGPU/WGSL/AST/Expressions/TypeConversion.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/Expressions/TypeConversion.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/Expressions/TypeConversion.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "_expression_.h"
+#include "TypeDecl.h"
 #include <wtf/UniqueRef.h>
 #include <wtf/Vector.h>
 

Modified: trunk/Source/WebGPU/WGSL/AST/FunctionDecl.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/FunctionDecl.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/FunctionDecl.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -28,6 +28,7 @@
 #include "ASTNode.h"
 #include "Attribute.h"
 #include "CompilationMessage.h"
+#include "GlobalDecl.h"
 #include "Statements/CompoundStatement.h"
 #include "TypeDecl.h"
 
@@ -46,6 +47,7 @@
 
     const StringView& name() const { return m_name; }
     TypeDecl& type() { return m_type; }
+    Attributes& attributes() { return m_attributes; }
 
 private:
     StringView m_name;

Modified: trunk/Source/WebGPU/WGSL/AST/ShaderModule.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/ShaderModule.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/ShaderModule.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -26,8 +26,11 @@
 #pragma once
 
 #include "ASTNode.h"
+#include "FunctionDecl.h"
 #include "GlobalDecl.h"
 #include "GlobalDirective.h"
+#include "GlobalVariableDecl.h"
+#include "StructureDecl.h"
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>

Modified: trunk/Source/WebGPU/WGSL/AST/Statements/AssignmentStatement.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/Statements/AssignmentStatement.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/Statements/AssignmentStatement.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -27,6 +27,7 @@
 
 #include "_expression_.h"
 #include "Statement.h"
+#include <wtf/UniqueRef.h>
 
 namespace WGSL::AST {
 

Modified: trunk/Source/WebGPU/WGSL/AST/StructureDecl.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/StructureDecl.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/StructureDecl.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -50,6 +50,7 @@
 
     const StringView& name() const { return m_name; }
     TypeDecl& type() { return m_type; }
+    Attributes& attributes() { return m_attributes; }
 
 private:
     StringView m_name;

Modified: trunk/Source/WebGPU/WGSL/AST/TypeDecl.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/AST/TypeDecl.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/AST/TypeDecl.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -92,6 +92,35 @@
     {
     }
 
+    static std::optional<Base> stringViewToKind(StringView& view)
+    {
+        if (view == "vec2")
+            return Base::Vec2;
+        if (view == "vec3")
+            return Base::Vec3;
+        if (view == "vec4")
+            return Base::Vec4;
+        if (view == "mat2x2")
+            return Base::Mat2x2;
+        if (view == "mat2x3")
+            return Base::Mat2x3;
+        if (view == "mat2x4")
+            return Base::Mat2x4;
+        if (view == "mat3x2")
+            return Base::Mat3x2;
+        if (view == "mat3x3")
+            return Base::Mat3x3;
+        if (view == "mat3x4")
+            return Base::Mat3x4;
+        if (view == "mat4x2")
+            return Base::Mat4x2;
+        if (view == "mat4x3")
+            return Base::Mat4x3;
+        if (view == "mat4x4")
+            return Base::Mat4x4;
+        return std::nullopt;
+    }
+
     Kind kind() const override { return Kind::Parameterized; }
     Base base() const { return m_base; }
     TypeDecl& elementType() { return m_elementType; }

Modified: trunk/Source/WebGPU/WGSL/CompilationMessage.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/CompilationMessage.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/CompilationMessage.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -53,4 +53,7 @@
     SourceSpan m_span;
 };
 
+using Warning = CompilationMessage;
+using Error = CompilationMessage;
+
 } // namespace WGSL

Added: trunk/Source/WebGPU/WGSL/Parser.cpp (0 => 291075)


--- trunk/Source/WebGPU/WGSL/Parser.cpp	                        (rev 0)
+++ trunk/Source/WebGPU/WGSL/Parser.cpp	2022-03-09 22:25:11 UTC (rev 291075)
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Parser.h"
+#include "config.h"
+
+#include "AST/Attribute.h"
+#include "AST/_expression_.h"
+#include "AST/Expressions/IdentifierExpression.h"
+#include "AST/Expressions/LiteralExpressions.h"
+#include "AST/Expressions/StructureAccess.h"
+#include "AST/Expressions/TypeConversion.h"
+#include "AST/GlobalDecl.h"
+#include "AST/Statement.h"
+#include "AST/Statements/AssignmentStatement.h"
+#include "AST/Statements/CompoundStatement.h"
+#include "AST/Statements/ReturnStatement.h"
+#include "AST/StructureDecl.h"
+#include "Lexer.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WGSL {
+
+#define START_PARSE() \
+    auto _startOfElementPosition = m_lexer.currentPosition();
+
+#define CURRENT_SOURCE_SPAN() \
+    SourceSpan(_startOfElementPosition, m_lexer.currentPosition())
+
+#define RETURN_NODE(type, ...) \
+    do { \
+        AST::type astNodeResult(CURRENT_SOURCE_SPAN(), __VA_ARGS__); \
+        return { WTFMove(astNodeResult) }; \
+    } while (false)
+
+// Passing 0 arguments beyond the type to RETURN_NODE is invalid because of a stupid limitation of the C preprocessor
+#define RETURN_NODE_NO_ARGS(type) \
+    do { \
+        AST::type astNodeResult(CURRENT_SOURCE_SPAN()); \
+        return { WTFMove(astNodeResult) }; \
+    } while (false)
+
+#define RETURN_NODE_REF(type, ...) \
+    return { makeUniqueRef<AST::type>(CURRENT_SOURCE_SPAN(), __VA_ARGS__) };
+
+// Passing 0 arguments beyond the type to RETURN_NODE_REF is invalid because of a stupid limitation of the C preprocessor
+#define RETURN_NODE_REF_NO_ARGS(type) \
+    return { makeUniqueRef<AST::type>(CURRENT_SOURCE_SPAN()) };
+
+#define FAIL(string) \
+    return makeUnexpected(Error(string, CURRENT_SOURCE_SPAN()));
+
+// Warning: cannot use the do..while trick because it defines a new identifier named `name`.
+// So do not use after an if/for/while without braces.
+#define PARSE(name, element, ...) \
+    auto name##Expected = parse##element(__VA_ARGS__); \
+    if (!name##Expected) \
+        return makeUnexpected(name##Expected.error()); \
+    auto& name = *name##Expected;
+
+// Warning: cannot use the do..while trick because it defines a new identifier named `name`.
+// So do not use after an if/for/while without braces.
+#define CONSUME_TYPE_NAMED(name, type) \
+    auto name##Expected = consumeType(TokenType::type); \
+    if (!name##Expected) { \
+        StringBuilder builder; \
+        builder.append("Expected a "); \
+        builder.append(toString(TokenType::type)); \
+        builder.append(", but got a "); \
+        builder.append(toString(name##Expected.error())); \
+        FAIL(builder.toString()); \
+    } \
+    auto& name = *name##Expected;
+
+#define CONSUME_TYPE(type) \
+    do { \
+        auto expectedToken = consumeType(TokenType::type); \
+        if (!expectedToken) { \
+            StringBuilder builder; \
+            builder.append("Expected a "); \
+            builder.append(toString(TokenType::type)); \
+            builder.append(", but got a "); \
+            builder.append(toString(expectedToken.error())); \
+            FAIL(builder.toString()); \
+        } \
+    } while (false)
+
+template<typename Lexer>
+class Parser {
+public:
+    Parser(Lexer& lexer)
+        : m_lexer(lexer)
+        , m_current(lexer.lex())
+    {
+    }
+
+    Expected<AST::ShaderModule, Error> parseShader();
+
+private:
+    // UniqueRef whenever it can return multiple types.
+    Expected<UniqueRef<AST::GlobalDecl>, Error> parseGlobalDecl();
+    Expected<AST::Attributes, Error> parseAttributes();
+    Expected<UniqueRef<AST::Attribute>, Error> parseAttribute();
+    Expected<AST::StructDecl, Error> parseStructDecl(AST::Attributes&&);
+    Expected<AST::StructMember, Error> parseStructMember();
+    Expected<UniqueRef<AST::TypeDecl>, Error> parseTypeDecl();
+    Expected<UniqueRef<AST::TypeDecl>, Error> parseTypeDeclAfterIdentifier(StringView&&, SourcePosition start);
+    Expected<AST::GlobalVariableDecl, Error> parseGlobalVariableDecl(AST::Attributes&&);
+    Expected<AST::VariableQualifier, Error> parseVariableQualifier();
+    Expected<AST::StorageClass, Error> parseStorageClass();
+    Expected<AST::AccessMode, Error> parseAccessMode();
+    Expected<AST::FunctionDecl, Error> parseFunctionDecl(AST::Attributes&&);
+    Expected<AST::Parameter, Error> parseParameter();
+    Expected<UniqueRef<AST::Statement>, Error> parseStatement();
+    Expected<AST::CompoundStatement, Error> parseCompoundStatement();
+    Expected<AST::ReturnStatement, Error> parseReturnStatement();
+    Expected<UniqueRef<AST::_expression_>, Error> parseShortCircuitOrExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseRelationalExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseShiftExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseAdditiveExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseMultiplicativeExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseUnaryExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseSingularExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parsePostfixExpression(UniqueRef<AST::_expression_>&& base, SourcePosition startPosition);
+    Expected<UniqueRef<AST::_expression_>, Error> parsePrimaryExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseLHSExpression();
+    Expected<UniqueRef<AST::_expression_>, Error> parseCoreLHSExpression();
+    Expected<Vector<UniqueRef<AST::_expression_>>, Error> parseArgumentExpressionList();
+
+    Expected<Token, TokenType> consumeType(TokenType);
+    void consume();
+
+    Token& current() { return m_current; }
+
+    Lexer& m_lexer;
+    Token m_current;
+};
+
+template<typename Lexer>
+Expected<AST::ShaderModule, Error> parse(const String& wgsl)
+{
+    Lexer lexer(wgsl);
+    Parser parser(lexer);
+    
+    return parser.parseShader();
+}
+
+Expected<AST::ShaderModule, Error> parseLChar(const String& wgsl)
+{
+    return parse<Lexer<LChar>>(wgsl);
+}
+
+Expected<AST::ShaderModule, Error> parseUChar(const String& wgsl)
+{
+    return parse<Lexer<UChar>>(wgsl);
+}
+
+template<typename Lexer>
+Expected<Token, TokenType> Parser<Lexer>::consumeType(TokenType type)
+{
+    if (current().m_type == type) {
+        Expected<Token, TokenType> result = { m_current };
+        m_current = m_lexer.lex();
+        return result;
+    }
+    return makeUnexpected(current().m_type);
+}
+
+template<typename Lexer>
+void Parser<Lexer>::consume()
+{
+    m_current = m_lexer.lex();
+}
+
+template<typename Lexer>
+Expected<AST::ShaderModule, Error> Parser<Lexer>::parseShader()
+{
+    START_PARSE();
+
+    Vector<UniqueRef<AST::GlobalDirective>> directives;
+    // FIXME: parse directives here.
+
+    Vector<UniqueRef<AST::GlobalDecl>> decls;
+    while (!m_lexer.isAtEndOfFile()) {
+        PARSE(globalDecl, GlobalDecl)
+        decls.append(WTFMove(globalDecl));
+    }
+
+    RETURN_NODE(ShaderModule, WTFMove(directives), WTFMove(decls));
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::GlobalDecl>, Error> Parser<Lexer>::parseGlobalDecl()
+{
+    START_PARSE();
+
+    PARSE(attributes, Attributes);
+
+    switch (current().m_type) {
+    case TokenType::KeywordStruct: {
+        PARSE(structDecl, StructDecl, WTFMove(attributes));
+        return { makeUniqueRef<AST::StructDecl>(WTFMove(structDecl)) };
+    }
+    case TokenType::KeywordVar: {
+        PARSE(varDecl, GlobalVariableDecl, WTFMove(attributes));
+        CONSUME_TYPE(Semicolon);
+        return { makeUniqueRef<AST::GlobalVariableDecl>(WTFMove(varDecl)) };
+    }
+    case TokenType::KeywordFn: {
+        PARSE(fn, FunctionDecl, WTFMove(attributes));
+        return { makeUniqueRef<AST::FunctionDecl>(WTFMove(fn)) };
+    }
+    default:
+        FAIL("Trying to parse a GlobalDecl, expected 'var', 'fn', or 'struct'.");
+    }
+}
+
+template<typename Lexer>
+Expected<AST::Attributes, Error> Parser<Lexer>::parseAttributes()
+{
+    AST::Attributes attributes;
+
+    while (current().m_type == TokenType::Attribute) {
+        PARSE(firstAttribute, Attribute);
+        attributes.append(WTFMove(firstAttribute));
+    }
+
+    return { WTFMove(attributes) };
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::Attribute>, Error> Parser<Lexer>::parseAttribute()
+{
+    START_PARSE();
+
+    CONSUME_TYPE(Attribute);
+    CONSUME_TYPE_NAMED(ident, Identifier);
+    if (ident.m_ident == "group") {
+        CONSUME_TYPE(ParenLeft);
+        // FIXME: should more kinds of literals be accepted here?
+        CONSUME_TYPE_NAMED(id, IntegerLiteral);
+        CONSUME_TYPE(ParenRight);
+        RETURN_NODE_REF(GroupAttribute, id.m_literalValue);
+    }
+    if (ident.m_ident == "binding") {
+        CONSUME_TYPE(ParenLeft);
+        // FIXME: should more kinds of literals be accepted here?
+        CONSUME_TYPE_NAMED(id, IntegerLiteral);
+        CONSUME_TYPE(ParenRight);
+        RETURN_NODE_REF(BindingAttribute, id.m_literalValue);
+    }
+    if (ident.m_ident == "stage") {
+        CONSUME_TYPE(ParenLeft);
+        CONSUME_TYPE_NAMED(stage, Identifier);
+        CONSUME_TYPE(ParenRight);
+        if (stage.m_ident == "compute")
+            RETURN_NODE_REF(StageAttribute, AST::StageAttribute::Stage::Compute);
+        if (stage.m_ident == "vertex")
+            RETURN_NODE_REF(StageAttribute, AST::StageAttribute::Stage::Vertex);
+        if (stage.m_ident == "fragment")
+            RETURN_NODE_REF(StageAttribute, AST::StageAttribute::Stage::Fragment);
+        FAIL("Invalid stage attribute, the only options are 'compute', 'vertex', 'fragment'.");
+    }
+    if (ident.m_ident == "location") {
+        CONSUME_TYPE(ParenLeft);
+        // FIXME: should more kinds of literals be accepted here?
+        CONSUME_TYPE_NAMED(id, IntegerLiteral);
+        CONSUME_TYPE(ParenRight);
+        RETURN_NODE_REF(LocationAttribute, id.m_literalValue);
+    }
+    if (ident.m_ident == "builtin") {
+        CONSUME_TYPE(ParenLeft);
+        CONSUME_TYPE_NAMED(name, Identifier);
+        CONSUME_TYPE(ParenRight);
+        RETURN_NODE_REF(BuiltinAttribute, name.m_ident);
+    }
+    FAIL("Unknown attribute, the only supported attributes are 'group', 'binding', 'stage'.");
+}
+
+template<typename Lexer>
+Expected<AST::StructDecl, Error> Parser<Lexer>::parseStructDecl(AST::Attributes&& attributes)
+{
+    START_PARSE();
+
+    CONSUME_TYPE(KeywordStruct);
+    CONSUME_TYPE_NAMED(name, Identifier);
+    CONSUME_TYPE(BraceLeft);
+
+    Vector<UniqueRef<AST::StructMember>> members;
+    while (current().m_type != TokenType::BraceRight) {
+        PARSE(member, StructMember);
+        members.append(makeUniqueRef<AST::StructMember>(WTFMove(member)));
+    }
+
+    CONSUME_TYPE(BraceRight);
+
+    RETURN_NODE(StructDecl, name.m_ident, WTFMove(members), WTFMove(attributes));
+}
+
+template<typename Lexer>
+Expected<AST::StructMember, Error> Parser<Lexer>::parseStructMember()
+{
+    START_PARSE();
+
+    PARSE(attributes, Attributes);
+    CONSUME_TYPE_NAMED(name, Identifier);
+    CONSUME_TYPE(Colon);
+    PARSE(type, TypeDecl);
+    CONSUME_TYPE(Semicolon);
+
+    RETURN_NODE(StructMember, name.m_ident, WTFMove(type), WTFMove(attributes));
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::TypeDecl>, Error> Parser<Lexer>::parseTypeDecl()
+{
+    START_PARSE();
+
+    if (current().m_type == TokenType::KeywordI32) {
+        consume();
+        RETURN_NODE_REF(NamedType, StringView { "i32" });
+    }
+    if (current().m_type == TokenType::KeywordF32) {
+        consume();
+        RETURN_NODE_REF(NamedType, StringView { "f32" });
+    }
+    if (current().m_type == TokenType::KeywordU32) {
+        consume();
+        RETURN_NODE_REF(NamedType, StringView { "u32" });
+    }
+    if (current().m_type == TokenType::KeywordBool) {
+        consume();
+        RETURN_NODE_REF(NamedType, StringView { "bool" });
+    }
+    if (current().m_type == TokenType::Identifier) {
+        CONSUME_TYPE_NAMED(name, Identifier);
+        return parseTypeDeclAfterIdentifier(WTFMove(name.m_ident), _startOfElementPosition);
+    }
+
+    FAIL("Tried parsing a type and it did not start with an identifier");
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::TypeDecl>, Error> Parser<Lexer>::parseTypeDeclAfterIdentifier(StringView&& name, SourcePosition _startOfElementPosition)
+{
+    if (auto kind = AST::ParameterizedType::stringViewToKind(name)) {
+        CONSUME_TYPE(LT);
+        PARSE(elementType, TypeDecl);
+        CONSUME_TYPE(GT);
+        RETURN_NODE_REF(ParameterizedType, *kind, WTFMove(elementType));
+    }
+    RETURN_NODE_REF(NamedType, WTFMove(name));
+}
+
+template<typename Lexer>
+Expected<AST::GlobalVariableDecl, Error> Parser<Lexer>::parseGlobalVariableDecl(AST::Attributes&& attributes)
+{
+    START_PARSE();
+
+    CONSUME_TYPE(KeywordVar);
+
+    std::unique_ptr<AST::VariableQualifier> maybeQualifier = nullptr;
+    if (current().m_type == TokenType::LT) {
+        PARSE(variableQualifier, VariableQualifier);
+        maybeQualifier = WTF::makeUnique<AST::VariableQualifier>(WTFMove(variableQualifier));
+    }
+
+    CONSUME_TYPE_NAMED(name, Identifier);
+
+    std::unique_ptr<AST::TypeDecl> maybeType = nullptr;
+    if (current().m_type == TokenType::Colon) {
+        consume();
+        PARSE(typeDecl, TypeDecl);
+        maybeType = typeDecl.moveToUniquePtr();
+    }
+
+    std::unique_ptr<AST::_expression_> maybeInitializer = nullptr;
+    // FIXME: initializer
+
+    RETURN_NODE(GlobalVariableDecl, name.m_ident, WTFMove(maybeQualifier), WTFMove(maybeType), WTFMove(maybeInitializer), WTFMove(attributes));
+}
+
+template<typename Lexer>
+Expected<AST::VariableQualifier, Error> Parser<Lexer>::parseVariableQualifier()
+{
+    START_PARSE();
+
+    CONSUME_TYPE(LT);
+    PARSE(storageClass, StorageClass);
+
+    // FIXME: verify that Read is the correct default in all cases.
+    AST::AccessMode accessMode = AST::AccessMode::Read;
+    if (current().m_type == TokenType::Comma) {
+        consume();
+        PARSE(actualAccessMode, AccessMode);
+        accessMode = actualAccessMode;
+    }
+
+    CONSUME_TYPE(GT);
+
+    RETURN_NODE(VariableQualifier, storageClass, accessMode);
+}
+
+template<typename Lexer>
+Expected<AST::StorageClass, Error> Parser<Lexer>::parseStorageClass()
+{
+    START_PARSE();
+
+    if (current().m_type == TokenType::KeywordFunction) {
+        consume();
+        return { AST::StorageClass::Function };
+    }
+    if (current().m_type == TokenType::KeywordPrivate) {
+        consume();
+        return { AST::StorageClass::Private };
+    }
+    if (current().m_type == TokenType::KeywordWorkgroup) {
+        consume();
+        return { AST::StorageClass::Workgroup };
+    }
+    if (current().m_type == TokenType::KeywordUniform) {
+        consume();
+        return { AST::StorageClass::Uniform };
+    }
+    if (current().m_type == TokenType::KeywordStorage) {
+        consume();
+        return { AST::StorageClass::Storage };
+    }
+
+    FAIL("Expected one of 'function'/'private'/'storage'/'uniform'/'workgroup'");
+}
+
+template<typename Lexer>
+Expected<AST::AccessMode, Error> Parser<Lexer>::parseAccessMode()
+{
+    START_PARSE();
+
+    if (current().m_type == TokenType::KeywordRead) {
+        consume();
+        return { AST::AccessMode::Read };
+    }
+    if (current().m_type == TokenType::KeywordWrite) {
+        consume();
+        return { AST::AccessMode::Write };
+    }
+    if (current().m_type == TokenType::KeywordReadWrite) {
+        consume();
+        return { AST::AccessMode::ReadWrite };
+    }
+
+    FAIL("Expected one of 'read'/'write'/'read_write'");
+}
+
+template<typename Lexer>
+Expected<AST::FunctionDecl, Error> Parser<Lexer>::parseFunctionDecl(AST::Attributes&& attributes)
+{
+    START_PARSE();
+
+    CONSUME_TYPE(KeywordFn);
+    CONSUME_TYPE_NAMED(name, Identifier);
+
+    CONSUME_TYPE(ParenLeft);
+    Vector<UniqueRef<AST::Parameter>> parameters;
+    while (current().m_type != TokenType::ParenRight) {
+        PARSE(parameter, Parameter);
+        parameters.append(makeUniqueRef<AST::Parameter>(WTFMove(parameter)));
+    }
+    CONSUME_TYPE(ParenRight);
+
+    AST::Attributes returnAttributes;
+    std::unique_ptr<AST::TypeDecl> maybeReturnType = nullptr;
+    if (current().m_type == TokenType::Arrow) {
+        consume();
+        PARSE(parsedReturnAttributes, Attributes);
+        returnAttributes = WTFMove(parsedReturnAttributes);
+        PARSE(type, TypeDecl);
+        maybeReturnType = type.moveToUniquePtr();
+    }
+
+    PARSE(body, CompoundStatement);
+
+    RETURN_NODE(FunctionDecl, name.m_ident, WTFMove(parameters), WTFMove(maybeReturnType), WTFMove(body), WTFMove(attributes), WTFMove(returnAttributes));
+}
+
+template<typename Lexer>
+Expected<AST::Parameter, Error> Parser<Lexer>::parseParameter()
+{
+    START_PARSE();
+
+    PARSE(attributes, Attributes);
+    CONSUME_TYPE_NAMED(name, Identifier)
+    CONSUME_TYPE(Colon);
+    PARSE(type, TypeDecl);
+
+    RETURN_NODE(Parameter, name.m_ident, WTFMove(type), WTFMove(attributes));
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::Statement>, Error> Parser<Lexer>::parseStatement()
+{
+    START_PARSE();
+
+    switch (current().m_type) {
+    case TokenType::BraceLeft: {
+        PARSE(compoundStmt, CompoundStatement);
+        return { makeUniqueRef<AST::CompoundStatement>(WTFMove(compoundStmt)) };
+    }
+    case TokenType::Semicolon: {
+        consume();
+        Vector<UniqueRef<AST::Statement>> statements;
+        return { makeUniqueRef<AST::CompoundStatement>(CURRENT_SOURCE_SPAN(), WTFMove(statements)) };
+    }
+    case TokenType::KeywordReturn: {
+        PARSE(returnStmt, ReturnStatement);
+        CONSUME_TYPE(Semicolon);
+        return { makeUniqueRef<AST::ReturnStatement>(WTFMove(returnStmt)) };
+    }
+    case TokenType::Identifier: {
+        // FIXME: there will be other cases here eventually for function calls
+        PARSE(lhs, LHSExpression);
+        CONSUME_TYPE(Equal);
+        PARSE(rhs, _expression_);
+        CONSUME_TYPE(Semicolon);
+        RETURN_NODE_REF(AssignmentStatement, lhs.moveToUniquePtr(), WTFMove(rhs));
+    }
+    default:
+        FAIL("Not a valid statement");
+    }
+}
+
+template<typename Lexer>
+Expected<AST::CompoundStatement, Error> Parser<Lexer>::parseCompoundStatement()
+{
+    START_PARSE();
+
+    CONSUME_TYPE(BraceLeft);
+
+    Vector<UniqueRef<AST::Statement>> statements;
+    while (current().m_type != TokenType::BraceRight) {
+        PARSE(stmt, Statement);
+        statements.append(WTFMove(stmt));
+    }
+
+    CONSUME_TYPE(BraceRight);
+
+    RETURN_NODE(CompoundStatement, WTFMove(statements));
+}
+
+template<typename Lexer>
+Expected<AST::ReturnStatement, Error> Parser<Lexer>::parseReturnStatement()
+{
+    START_PARSE();
+
+    CONSUME_TYPE(KeywordReturn);
+
+    if (current().m_type == TokenType::Semicolon) {
+        RETURN_NODE(ReturnStatement, { });
+    }
+
+    PARSE(expr, ShortCircuitOrExpression);
+    RETURN_NODE(ReturnStatement, expr.moveToUniquePtr());
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseShortCircuitOrExpression()
+{
+    // FIXME: fill in
+    return parseRelationalExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseRelationalExpression()
+{
+    // FIXME: fill in
+    return parseShiftExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseShiftExpression()
+{
+    // FIXME: fill in
+    return parseAdditiveExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseAdditiveExpression()
+{
+    // FIXME: fill in
+    return parseMultiplicativeExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseMultiplicativeExpression()
+{
+    // FIXME: fill in
+    return parseUnaryExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseUnaryExpression()
+{
+    // FIXME: fill in
+    return parseSingularExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseSingularExpression()
+{
+    START_PARSE();
+    PARSE(base, PrimaryExpression);
+    return parsePostfixExpression(WTFMove(base), _startOfElementPosition);
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parsePostfixExpression(UniqueRef<AST::_expression_>&& base, SourcePosition startPosition)
+{
+    START_PARSE();
+
+    UniqueRef<AST::_expression_> expr = WTFMove(base);
+    // FIXME: add the case for array/vector/matrix access
+    while (current().m_type == TokenType::Period) {
+        consume();
+        CONSUME_TYPE_NAMED(fieldName, Identifier);
+        SourceSpan span(startPosition, m_lexer.currentPosition());
+        expr = makeUniqueRef<AST::StructureAccess>(span, WTFMove(expr), fieldName.m_ident);
+    }
+
+    return { WTFMove(expr) };
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parsePrimaryExpression()
+{
+    START_PARSE();
+
+    switch (current().m_type) {
+    case TokenType::ParenLeft: {
+        consume();
+        PARSE(expr, _expression_);
+        CONSUME_TYPE(ParenRight);
+        return { WTFMove(expr) };
+    }
+    case TokenType::Identifier: {
+        CONSUME_TYPE_NAMED(ident, Identifier);
+        if (ident.m_ident == "true") {
+            RETURN_NODE_REF(BoolLiteral, true);
+        }
+        if (ident.m_ident == "false") {
+            RETURN_NODE_REF(BoolLiteral, false);
+        }
+        if (current().m_type == TokenType::LT || current().m_type == TokenType::ParenLeft) {
+            PARSE(type, TypeDeclAfterIdentifier, WTFMove(ident.m_ident), _startOfElementPosition);
+            PARSE(arguments, ArgumentExpressionList);
+            RETURN_NODE_REF(TypeConversion, WTFMove(type), WTFMove(arguments));
+        }
+        RETURN_NODE_REF(IdentifierExpression, ident.m_ident);
+    }
+    case TokenType::IntegerLiteralSigned: {
+        CONSUME_TYPE_NAMED(lit, IntegerLiteralSigned);
+        RETURN_NODE_REF(Int32Literal, lit.m_literalValue);
+    }
+    case TokenType::IntegerLiteralUnsigned: {
+        CONSUME_TYPE_NAMED(lit, IntegerLiteralUnsigned);
+        RETURN_NODE_REF(Uint32Literal, lit.m_literalValue);
+    }
+    case TokenType::DecimalFloatLiteral: {
+        CONSUME_TYPE_NAMED(lit, DecimalFloatLiteral);
+        RETURN_NODE_REF(Float32Literal, lit.m_literalValue);
+    }
+    // FIXME: HexFloatLiteral and IntegerLiteral
+    default:
+        break;
+    }
+    FAIL("Expected one of '(', a literal, or an identifier");
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseExpression()
+{
+    // FIXME: Fill in
+    return parseRelationalExpression();
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseLHSExpression()
+{
+    START_PARSE();
+
+    // FIXME: Add the possibility of a prefix
+    PARSE(base, CoreLHSExpression);
+    return parsePostfixExpression(WTFMove(base), _startOfElementPosition);
+}
+
+template<typename Lexer>
+Expected<UniqueRef<AST::_expression_>, Error> Parser<Lexer>::parseCoreLHSExpression()
+{
+    START_PARSE();
+
+    switch (current().m_type) {
+    case TokenType::ParenLeft: {
+        consume();
+        PARSE(expr, LHSExpression);
+        CONSUME_TYPE(ParenRight);
+        return { WTFMove(expr) };
+    }
+    case TokenType::Identifier: {
+        CONSUME_TYPE_NAMED(ident, Identifier);
+        RETURN_NODE_REF(IdentifierExpression, ident.m_ident);
+    }
+    default:
+        break;
+    }
+
+    FAIL("Tried to parse the left-hand side of an assignment and failed");
+}
+
+template<typename Lexer>
+Expected<Vector<UniqueRef<AST::_expression_>>, Error> Parser<Lexer>::parseArgumentExpressionList()
+{
+    START_PARSE();
+    CONSUME_TYPE(ParenLeft);
+
+    Vector<UniqueRef<AST::_expression_>> arguments;
+    while (current().m_type != TokenType::ParenRight) {
+        PARSE(expr, _expression_);
+        arguments.append(WTFMove(expr));
+        if (current().m_type != TokenType::ParenRight) {
+            CONSUME_TYPE(Comma);
+        }
+    }
+
+    CONSUME_TYPE(ParenRight);
+    return { WTFMove(arguments) };
+}
+
+} // namespace WGSL

Copied: trunk/Source/WebGPU/WGSL/Parser.h (from rev 291068, trunk/Source/WebGPU/WGSL/CompilationMessage.h) (0 => 291075)


--- trunk/Source/WebGPU/WGSL/Parser.h	                        (rev 0)
+++ trunk/Source/WebGPU/WGSL/Parser.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AST/ShaderModule.h"
+#include "CompilationMessage.h"
+#include "Lexer.h"
+#include <wtf/Expected.h>
+
+namespace WGSL {
+
+template<typename Lexer>
+Expected<AST::ShaderModule, Error> parse(const String& wgsl);
+
+Expected<AST::ShaderModule, Error> parseLChar(const String& wgsl);
+Expected<AST::ShaderModule, Error> parseUChar(const String& wgsl);
+
+} // namespace WGSL

Modified: trunk/Source/WebGPU/WGSL/WGSL.cpp (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/WGSL.cpp	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/WGSL.cpp	2022-03-09 22:25:11 UTC (rev 291075)
@@ -26,31 +26,32 @@
 #include "config.h"
 #include "WGSL.h"
 
-#include "Lexer.h"
-// All of these are just to check that they compile, since for now they are not really used.
-#include "AST/GlobalVariableDecl.h"
-#include "AST/StructureDecl.h"
-#include "AST/FunctionDecl.h"
-#include "AST/ShaderModule.h"
-#include "AST/Statements/AssignmentStatement.h"
-#include "AST/Statements/ReturnStatement.h"
-#include "AST/Expressions/IdentifierExpression.h"
-#include "AST/Expressions/TypeConversion.h"
-#include "AST/Expressions/StructureAccess.h"
-#include "AST/Expressions/LiteralExpressions.h"
+#include "Parser.h"
 
 namespace WGSL {
 
-std::variant<SuccessfulCheck, FailedCheck> staticCheck(const String& str, const std::optional<SourceMap>&)
+std::variant<SuccessfulCheck, FailedCheck> staticCheck(const String& wgsl, const std::optional<SourceMap>&)
 {
-    // Making sure that the lexer builds correctly, will be removed in later patches
-    Lexer<LChar> lexer(str);
-    lexer.lex();
-    return FailedCheck { { }, { } };
+    Expected<AST::ShaderModule, Error> parserResult = wgsl.is8Bit() ? parseLChar(wgsl) : parseUChar(wgsl);
+    if (!parserResult.has_value()) {
+        // FIXME: Add support for returning multiple errors from the parser.
+        return FailedCheck { { parserResult.error() }, { /* warnings */ } };
+    }
+    UniqueRef<AST::ShaderModule> shader = makeUniqueRef<AST::ShaderModule>(WTFMove(parserResult.value()));
+
+    Vector<Warning> warnings { };
+    // FIXME: add validation
+    return std::variant<SuccessfulCheck, FailedCheck>(std::in_place_type<SuccessfulCheck>, WTFMove(warnings), WTFMove(shader));
 }
 
 SuccessfulCheck::SuccessfulCheck(SuccessfulCheck&&) = default;
 
+SuccessfulCheck::SuccessfulCheck(Vector<Warning>&& messages, UniqueRef<AST::ShaderModule>&& shader)
+    : warnings(WTFMove(messages))
+    , ast(WTFMove(shader))
+{
+}
+
 SuccessfulCheck::~SuccessfulCheck() = default;
 
 PrepareResult prepare(const AST::ShaderModule& ast, const HashMap<String, PipelineLayout>& pipelineLayouts)

Modified: trunk/Source/WebGPU/WGSL/WGSL.h (291074 => 291075)


--- trunk/Source/WebGPU/WGSL/WGSL.h	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WGSL/WGSL.h	2022-03-09 22:25:11 UTC (rev 291075)
@@ -49,14 +49,15 @@
 struct SuccessfulCheck {
     SuccessfulCheck() = delete;
     SuccessfulCheck(SuccessfulCheck&&);
+    SuccessfulCheck(Vector<Warning>&&, UniqueRef<AST::ShaderModule>&&);
     ~SuccessfulCheck();
-    Vector<CompilationMessage> warnings;
+    Vector<Warning> warnings;
     UniqueRef<AST::ShaderModule> ast;
 };
 
 struct FailedCheck {
-    Vector<CompilationMessage> errors;
-    Vector<CompilationMessage> warnings;
+    Vector<Error> errors;
+    Vector<Warning> warnings;
 };
 
 struct SourceMap {

Added: trunk/Source/WebGPU/WGSLUnitTests/WGSLParserTests.mm (0 => 291075)


--- trunk/Source/WebGPU/WGSLUnitTests/WGSLParserTests.mm	                        (rev 0)
+++ trunk/Source/WebGPU/WGSLUnitTests/WGSLParserTests.mm	2022-03-09 22:25:11 UTC (rev 291075)
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#import "AssignmentStatement.h"
+#import "IdentifierExpression.h"
+#import "Lexer.h"
+#import "LiteralExpressions.h"
+#import "Parser.h"
+#import "ReturnStatement.h"
+#import "StructureAccess.h"
+#import "TypeConversion.h"
+#import "WGSL.h"
+#import <wtf/DataLog.h>
+#import <XCTest/XCTest.h>
+
+@interface WGSLParserTests : XCTestCase
+
+@end
+
+@implementation WGSLParserTests
+
+- (void)testParsingStruct {
+    auto shader = WGSL::parseLChar("struct B {\n"
+                        "    a: i32;\n"
+                        "}");
+    if (!shader.has_value())
+        dataLogLn(shader.error());
+    XCTAssert(shader.has_value());
+    XCTAssert(!shader->directives().size());
+    XCTAssert(shader->structs().size() == 1);
+    XCTAssert(shader->globalVars().size() == 0);
+    XCTAssert(shader->functions().size() == 0);
+    WGSL::AST::StructDecl& str = shader->structs()[0];
+    XCTAssert(str.name() == "B");
+    XCTAssert(str.attributes().isEmpty());
+    XCTAssert(str.members().size() == 1);
+    XCTAssert(str.members()[0]->attributes().isEmpty());
+    XCTAssert(str.members()[0]->name() == "a");
+    XCTAssert(str.members()[0]->type().isNamed());
+    WGSL::AST::NamedType& memberType = downcast<WGSL::AST::NamedType>(str.members()[0]->type());
+    XCTAssert(memberType.name() == "i32");
+}
+
+- (void)testParsingGlobalVariable {
+    auto shader = WGSL::parseLChar("@group(0) @binding(0)\n"
+                                   "var<storage, read_write> x: B;\n");
+    if (!shader.has_value())
+        dataLogLn(shader.error());
+    XCTAssert(shader.has_value());
+    XCTAssert(!shader->directives().size());
+    XCTAssert(shader->structs().size() == 0);
+    XCTAssert(shader->globalVars().size() == 1);
+    XCTAssert(shader->functions().size() == 0);
+    WGSL::AST::GlobalVariableDecl& var = shader->globalVars()[0];
+    XCTAssert(var.attributes().size() == 2);
+    XCTAssert(var.attributes()[0]->isGroup());
+    XCTAssert(downcast<WGSL::AST::GroupAttribute>(var.attributes()[0].get()).group() == 0);
+    XCTAssert(var.attributes()[1]->isBinding());
+    XCTAssert(downcast<WGSL::AST::BindingAttribute>(var.attributes()[1].get()).binding() == 0);
+    XCTAssert(var.name() == "x");
+    XCTAssert(var.maybeQualifier());
+    XCTAssert(var.maybeQualifier()->storageClass() == WGSL::AST::StorageClass::Storage);
+    XCTAssert(var.maybeQualifier()->accessMode() == WGSL::AST::AccessMode::ReadWrite);
+    XCTAssert(var.maybeTypeDecl());
+    XCTAssert(var.maybeTypeDecl()->isNamed());
+    WGSL::AST::NamedType& namedType = downcast<WGSL::AST::NamedType>(*var.maybeTypeDecl());
+    XCTAssert(namedType.name() == "B");
+    XCTAssert(!var.maybeInitializer());
+}
+
+- (void)testParsingFunctionDecl {
+    auto shader = WGSL::parseLChar("@stage(compute)\n"
+                                   "fn main() {\n"
+                                   "    x.a = 42i;\n"
+                                   "}");
+    if (!shader.has_value())
+        dataLogLn(shader.error());
+    XCTAssert(shader.has_value());
+    XCTAssert(!shader->directives().size());
+    XCTAssert(shader->structs().size() == 0);
+    XCTAssert(shader->globalVars().size() == 0);
+    XCTAssert(shader->functions().size() == 1);
+    WGSL::AST::FunctionDecl& func = shader->functions()[0];
+    XCTAssert(func.attributes().size() == 1);
+    XCTAssert(func.attributes()[0]->isStage());
+    XCTAssert(downcast<WGSL::AST::StageAttribute>(func.attributes()[0].get()).stage() == WGSL::AST::StageAttribute::Stage::Compute);
+    XCTAssert(func.name() == "main");
+    XCTAssert(func.parameters().size() == 0);
+    XCTAssert(func.returnAttributes().isEmpty());
+    XCTAssert(func.maybeReturnType() == nullptr);
+    XCTAssert(func.body().statements().size() == 1);
+    XCTAssert(func.body().statements()[0]->isAssignment());
+    WGSL::AST::AssignmentStatement& stmt = downcast<WGSL::AST::AssignmentStatement>(func.body().statements()[0].get());
+    XCTAssert(stmt.maybeLhs());
+    XCTAssert(stmt.maybeLhs()->isStructureAccess());
+    WGSL::AST::StructureAccess& structAccess = downcast<WGSL::AST::StructureAccess>(*stmt.maybeLhs());
+    XCTAssert(structAccess.base()->isIdentifier());
+    WGSL::AST::IdentifierExpression base = downcast<WGSL::AST::IdentifierExpression>(structAccess.base().get());
+    XCTAssert(base.identifier() == "x");
+    XCTAssert(structAccess.fieldName() == "a");
+    XCTAssert(stmt.rhs().isInt32Literal());
+    WGSL::AST::Int32Literal& rhs = downcast<WGSL::AST::Int32Literal>(stmt.rhs());
+    XCTAssert(rhs.value() == 42);
+}
+
+- (void)testTrivialGraphicsShader {
+    auto shader = WGSL::parseLChar("@stage(vertex)\n"
+                                   "fn vertexShader(@location(0) x: vec4<f32>) -> @builtin(position) vec4<f32> {\n"
+                                   "    return x;\n"
+                                   "}\n\n"
+                                   "@stage(fragment)\n"
+                                   "fn fragmentShader() -> @location(0) vec4<f32> {\n"
+                                   "    return vec4<f32>(0.4, 0.4, 0.8, 1.0);\n"
+                                   "}");
+    if (!shader.has_value())
+        dataLogLn(shader.error());
+    XCTAssert(shader.has_value());
+    XCTAssert(!shader->directives().size());
+    XCTAssert(shader->structs().size() == 0);
+    XCTAssert(shader->globalVars().size() == 0);
+    XCTAssert(shader->functions().size() == 2);
+
+    {
+        WGSL::AST::FunctionDecl& func = shader->functions()[0];
+        XCTAssert(func.attributes().size() == 1);
+        XCTAssert(func.attributes()[0]->isStage());
+        XCTAssert(downcast<WGSL::AST::StageAttribute>(func.attributes()[0].get()).stage() == WGSL::AST::StageAttribute::Stage::Vertex);
+        XCTAssert(func.name() == "vertexShader");
+        XCTAssert(func.parameters().size() == 1);
+        XCTAssert(func.parameters()[0]->name() == "x");
+        XCTAssert(func.parameters()[0]->attributes().size() == 1);
+        XCTAssert(func.parameters()[0]->attributes()[0]->isLocation());
+        XCTAssert(downcast<WGSL::AST::LocationAttribute>(func.parameters()[0]->attributes()[0].get()).location() == 0);
+        XCTAssert(func.parameters()[0]->type().isParameterized());
+        WGSL::AST::ParameterizedType& paramType = downcast<WGSL::AST::ParameterizedType>(func.parameters()[0]->type());
+        XCTAssert(paramType.base() == WGSL::AST::ParameterizedType::Base::Vec4);
+        XCTAssert(paramType.elementType().isNamed());
+        XCTAssert(downcast<WGSL::AST::NamedType>(paramType.elementType()).name() == "f32");
+        XCTAssert(func.returnAttributes().size() == 1);
+        XCTAssert(func.returnAttributes()[0]->isBuiltin());
+        XCTAssert(downcast<WGSL::AST::BuiltinAttribute>(func.returnAttributes()[0].get()).name() == "position");
+        XCTAssert(func.maybeReturnType());
+        XCTAssert(func.maybeReturnType()->isParameterized());
+        XCTAssert(func.body().statements().size() == 1);
+        XCTAssert(func.body().statements()[0]->isReturn());
+        WGSL::AST::ReturnStatement& stmt = downcast<WGSL::AST::ReturnStatement>(func.body().statements()[0].get());
+        XCTAssert(stmt.maybeExpression());
+        XCTAssert(stmt.maybeExpression()->isIdentifier());
+    }
+
+    {
+        WGSL::AST::FunctionDecl& func = shader->functions()[1];
+        XCTAssert(func.attributes().size() == 1);
+        XCTAssert(func.attributes()[0]->isStage());
+        XCTAssert(downcast<WGSL::AST::StageAttribute>(func.attributes()[0].get()).stage() == WGSL::AST::StageAttribute::Stage::Fragment);
+        XCTAssert(func.name() == "fragmentShader");
+        XCTAssert(func.parameters().size() == 0);
+        XCTAssert(func.returnAttributes().size() == 1);
+        XCTAssert(func.returnAttributes()[0]->isLocation());
+        XCTAssert(downcast<WGSL::AST::LocationAttribute>(func.returnAttributes()[0].get()).location() == 0);
+        XCTAssert(func.maybeReturnType());
+        XCTAssert(func.maybeReturnType()->isParameterized());
+        XCTAssert(func.body().statements().size() == 1);
+        XCTAssert(func.body().statements()[0]->isReturn());
+        WGSL::AST::ReturnStatement& stmt = downcast<WGSL::AST::ReturnStatement>(func.body().statements()[0].get());
+        XCTAssert(stmt.maybeExpression());
+        XCTAssert(stmt.maybeExpression()->isTypeConversion());
+        WGSL::AST::TypeConversion& expr = downcast<WGSL::AST::TypeConversion>(*stmt.maybeExpression());
+        XCTAssert(expr.typeDecl()->isParameterized());
+        XCTAssert(expr.arguments().size() == 4);
+        XCTAssert(expr.arguments()[0]->isFloat32Literal());
+        XCTAssert(expr.arguments()[1]->isFloat32Literal());
+        XCTAssert(expr.arguments()[2]->isFloat32Literal());
+        XCTAssert(expr.arguments()[3]->isFloat32Literal());
+    }
+}
+
+@end

Modified: trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj (291074 => 291075)


--- trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj	2022-03-09 22:16:38 UTC (rev 291074)
+++ trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj	2022-03-09 22:25:11 UTC (rev 291075)
@@ -48,13 +48,15 @@
 		338BB2D227B6B63F00E066AB /* SourceSpan.h in Headers */ = {isa = PBXBuildFile; fileRef = 338BB2D127B6B63F00E066AB /* SourceSpan.h */; };
 		338BB2D427B6B66C00E066AB /* Lexer.h in Headers */ = {isa = PBXBuildFile; fileRef = 338BB2D327B6B66C00E066AB /* Lexer.h */; };
 		338BB2D627B6B68700E066AB /* Lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 338BB2D527B6B68700E066AB /* Lexer.cpp */; };
-		DD05A35C27BF09C60096EFAB /* libWTF.a in Product Dependencies */ = {isa = PBXBuildFile; fileRef = 1CEBD8292716CAE700A5254D /* libWTF.a */; };
+		339B7B1827D7FFA40072BF9A /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 339B7B1727D7FFA40072BF9A /* Parser.h */; };
+		339B7B1B27D800090072BF9A /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 339B7B1A27D800090072BF9A /* Parser.cpp */; };
+		339B7B1D27D80A1C0072BF9A /* WGSLParserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 339B7B1C27D80A1C0072BF9A /* WGSLParserTests.mm */; };
+		339B7B1E27D816270072BF9A /* CompilationMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33EA186727BC1B1400A1DD52 /* CompilationMessage.cpp */; };
 		33EA185E27BC194F00A1DD52 /* ASTNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA185D27BC194F00A1DD52 /* ASTNode.h */; };
 		33EA186027BC198100A1DD52 /* GlobalDirective.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA185F27BC198100A1DD52 /* GlobalDirective.h */; };
 		33EA186227BC19C100A1DD52 /* GlobalDecl.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186127BC19C100A1DD52 /* GlobalDecl.h */; };
 		33EA186427BC1A1D00A1DD52 /* GlobalVariableDecl.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186327BC1A1D00A1DD52 /* GlobalVariableDecl.h */; };
 		33EA186627BC1AD500A1DD52 /* CompilationMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186527BC1AD500A1DD52 /* CompilationMessage.h */; };
-		33EA186827BC1B1400A1DD52 /* CompilationMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33EA186727BC1B1400A1DD52 /* CompilationMessage.cpp */; };
 		33EA186A27BC1BE600A1DD52 /* Attribute.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186927BC1BE600A1DD52 /* Attribute.h */; };
 		33EA186C27BC1CBC00A1DD52 /* _expression_.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186B27BC1CBC00A1DD52 /* _expression_.h */; };
 		33EA186E27BC1D4C00A1DD52 /* TypeDecl.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA186D27BC1D4C00A1DD52 /* TypeDecl.h */; };
@@ -70,6 +72,7 @@
 		33EA188427BC268600A1DD52 /* StructureAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA188327BC268600A1DD52 /* StructureAccess.h */; };
 		33EA188627BC26DF00A1DD52 /* TypeConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA188527BC26DF00A1DD52 /* TypeConversion.h */; };
 		33EA188827BC361E00A1DD52 /* LiteralExpressions.h in Headers */ = {isa = PBXBuildFile; fileRef = 33EA188727BC361E00A1DD52 /* LiteralExpressions.h */; };
+		DD05A35C27BF09C60096EFAB /* libWTF.a in Product Dependencies */ = {isa = PBXBuildFile; fileRef = 1CEBD8292716CAE700A5254D /* libWTF.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -201,6 +204,9 @@
 		338BB2D127B6B63F00E066AB /* SourceSpan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SourceSpan.h; sourceTree = "<group>"; };
 		338BB2D327B6B66C00E066AB /* Lexer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Lexer.h; sourceTree = "<group>"; };
 		338BB2D527B6B68700E066AB /* Lexer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Lexer.cpp; sourceTree = "<group>"; };
+		339B7B1727D7FFA40072BF9A /* Parser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Parser.h; sourceTree = "<group>"; };
+		339B7B1A27D800090072BF9A /* Parser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Parser.cpp; sourceTree = "<group>"; };
+		339B7B1C27D80A1C0072BF9A /* WGSLParserTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WGSLParserTests.mm; sourceTree = "<group>"; };
 		33EA185D27BC194F00A1DD52 /* ASTNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ASTNode.h; path = WGSL/ASTNode.h; sourceTree = SOURCE_ROOT; };
 		33EA185F27BC198100A1DD52 /* GlobalDirective.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalDirective.h; sourceTree = "<group>"; };
 		33EA186127BC19C100A1DD52 /* GlobalDecl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalDecl.h; sourceTree = "<group>"; };
@@ -265,6 +271,7 @@
 		1C023D3D27449070001DB734 /* WGSLUnitTests */ = {
 			isa = PBXGroup;
 			children = (
+				339B7B1C27D80A1C0072BF9A /* WGSLParserTests.mm */,
 				1C023D3E27449070001DB734 /* WGSLLexerTests.mm */,
 			);
 			path = WGSLUnitTests;
@@ -368,11 +375,12 @@
 				1CEBD8042716BFAB00A5254D /* config.h */,
 				33EA186527BC1AD500A1DD52 /* CompilationMessage.h */,
 				33EA186727BC1B1400A1DD52 /* CompilationMessage.cpp */,
-				338BB2D327B6B66C00E066AB /* Lexer.h */,
 				338BB2D527B6B68700E066AB /* Lexer.cpp */,
 				338BB2D327B6B66C00E066AB /* Lexer.h */,
 				338BB2D127B6B63F00E066AB /* SourceSpan.h */,
 				338BB2CF27B6B61B00E066AB /* Token.cpp */,
+				339B7B1727D7FFA40072BF9A /* Parser.h */,
+				339B7B1A27D800090072BF9A /* Parser.cpp */,
 				338BB2CD27B6B60200E066AB /* Token.h */,
 				1CEBD8022716BF8200A5254D /* WGSL.cpp */,
 				1CEBD7F72716B34400A5254D /* WGSL.h */,
@@ -472,6 +480,7 @@
 				33EA185E27BC194F00A1DD52 /* ASTNode.h in Headers */,
 				33EA188627BC26DF00A1DD52 /* TypeConversion.h in Headers */,
 				33EA186427BC1A1D00A1DD52 /* GlobalVariableDecl.h in Headers */,
+				339B7B1827D7FFA40072BF9A /* Parser.h in Headers */,
 				33EA187B27BC230E00A1DD52 /* CompoundStatement.h in Headers */,
 				33EA187627BC216B00A1DD52 /* FunctionDecl.h in Headers */,
 				338BB2D227B6B63F00E066AB /* SourceSpan.h in Headers */,
@@ -680,6 +689,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				1C023D3F27449070001DB734 /* WGSLLexerTests.mm in Sources */,
+				339B7B1D27D80A1C0072BF9A /* WGSLParserTests.mm in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -725,6 +735,8 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				339B7B1E27D816270072BF9A /* CompilationMessage.cpp in Sources */,
+				339B7B1B27D800090072BF9A /* Parser.cpp in Sources */,
 				338BB2D627B6B68700E066AB /* Lexer.cpp in Sources */,
 				338BB2D027B6B61B00E066AB /* Token.cpp in Sources */,
 				1CEBD8032716BF8200A5254D /* WGSL.cpp in Sources */,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to