blob: 55e98d82caeac525bc599613fb6d1b7a2a1913ec [file] [log] [blame] [edit]
/*
* 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 "config.h"
#include "Lexer.h"
namespace TestWGSLAPI {
class TestLexer : public WGSL::Lexer<LChar> {
using Base = WGSL::Lexer<LChar>;
public:
TestLexer(const String& input)
: Base(input)
, m_tokens(Base::lex())
{
}
WGSL::Token lex()
{
return m_tokens[m_index++];
}
private:
Vector<WGSL::Token> m_tokens;
unsigned m_index { 0 };
};
static WGSL::Token checkSingleToken(const String& string, WGSL::TokenType type)
{
TestLexer lexer(string);
WGSL::Token result = lexer.lex();
ASSERT(result.type == type);
EXPECT_EQ(result.type, type);
return result;
}
static void checkSingleIntegerLiteral(const String& string, WGSL::TokenType type, int64_t integerValue)
{
WGSL::Token result = checkSingleToken(string, type);
EXPECT_EQ(result.integerValue, integerValue);
}
static void checkSingleFloatLiteral(const String& string, WGSL::TokenType type, double floatValue)
{
WGSL::Token result = checkSingleToken(string, type);
EXPECT_EQ(result.floatValue, floatValue);
}
static WGSL::Token checkNextTokenIs(TestLexer& lexer, WGSL::TokenType type, unsigned lineNumber)
{
WGSL::Token result = lexer.lex();
EXPECT_EQ(result.type, type);
EXPECT_EQ(result.span.line, lineNumber);
return result;
}
static void checkNextTokenIsIdentifier(TestLexer& lexer, const String& ident, unsigned lineNumber)
{
WGSL::Token result = checkNextTokenIs(lexer, WGSL::TokenType::Identifier, lineNumber);
EXPECT_EQ(result.ident, ident);
}
static void checkNextTokenIsIntegerLiteral(TestLexer& lexer, WGSL::TokenType type, int64_t integerValue, unsigned lineNumber)
{
WGSL::Token result = checkNextTokenIs(lexer, type, lineNumber);
EXPECT_EQ(result.integerValue, integerValue);
}
static void checkNextTokenIsFloatLiteral(TestLexer& lexer, WGSL::TokenType type, double floatValue, unsigned lineNumber)
{
WGSL::Token result = checkNextTokenIs(lexer, type, lineNumber);
EXPECT_EQ(result.floatValue, floatValue);
}
static void checkNextTokensAreBuiltinAttr(TestLexer& lexer, const String& attr, unsigned lineNumber)
{
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "builtin"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIdentifier(lexer, attr, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
};
TEST(WGSLLexerTests, Comments)
{
using WGSL::TokenType;
checkSingleToken("// This is line-ending comment.\n"
"/* This is a block comment\n"
" that spans lines.\n"
" /* Block comments can nest.\n"
" */\n"
" But all block comments must terminate.\n"
"*/"_s, TokenType::EndOfFile);
}
TEST(WGSLLexerTests, SingleTokens)
{
using WGSL::TokenType;
checkSingleToken(""_s, TokenType::EndOfFile);
checkSingleIntegerLiteral("1"_s, TokenType::IntegerLiteral, 1);
checkSingleIntegerLiteral("0"_s, TokenType::IntegerLiteral, 0);
checkSingleIntegerLiteral("142"_s, TokenType::IntegerLiteral, 142);
checkSingleFloatLiteral("142f"_s, TokenType::FloatLiteral, 142.0);
checkSingleFloatLiteral("1.1"_s, TokenType::AbstractFloatLiteral, 1.1);
checkSingleFloatLiteral("0.4"_s, TokenType::AbstractFloatLiteral, 0.4);
checkSingleFloatLiteral("0123.456"_s, TokenType::AbstractFloatLiteral, 0123.456);
checkSingleToken("0123"_s, TokenType::Invalid);
checkSingleFloatLiteral("0123."_s, TokenType::AbstractFloatLiteral, 123);
checkSingleFloatLiteral(".456"_s, TokenType::AbstractFloatLiteral, 0.456);
checkSingleToken("."_s, TokenType::Period);
checkSingleFloatLiteral("42f"_s, TokenType::FloatLiteral, 42);
checkSingleFloatLiteral("42e0f"_s, TokenType::FloatLiteral, 42);
checkSingleFloatLiteral("042e0f"_s, TokenType::FloatLiteral, 42);
checkSingleToken("042f"_s, TokenType::Invalid);
checkSingleFloatLiteral("0123.f"_s, TokenType::FloatLiteral, 123);
checkSingleFloatLiteral(".456f"_s, TokenType::FloatLiteral, 0.456f);
checkSingleFloatLiteral("42e-3"_s, TokenType::AbstractFloatLiteral, 42e-3);
checkSingleFloatLiteral("42e-3f"_s, TokenType::FloatLiteral, 42e-3f);
}
TEST(WGSLLexerTests, KeywordTokens)
{
using WGSL::TokenType;
checkSingleToken("alias"_s, TokenType::KeywordAlias);
checkSingleToken("break"_s, TokenType::KeywordBreak);
checkSingleToken("case"_s, TokenType::KeywordCase);
checkSingleToken("const"_s, TokenType::KeywordConst);
checkSingleToken("const_assert"_s, TokenType::KeywordConstAssert);
checkSingleToken("continue"_s, TokenType::KeywordContinue);
checkSingleToken("default"_s, TokenType::KeywordDefault);
checkSingleToken("diagnostic"_s, TokenType::KeywordDiagnostic);
checkSingleToken("discard"_s, TokenType::KeywordDiscard);
checkSingleToken("else"_s, TokenType::KeywordElse);
checkSingleToken("enable"_s, TokenType::KeywordEnable);
checkSingleToken("false"_s, TokenType::KeywordFalse);
checkSingleToken("fn"_s, TokenType::KeywordFn);
checkSingleToken("for"_s, TokenType::KeywordFor);
checkSingleToken("if"_s, TokenType::KeywordIf);
checkSingleToken("let"_s, TokenType::KeywordLet);
checkSingleToken("loop"_s, TokenType::KeywordLoop);
checkSingleToken("override"_s, TokenType::KeywordOverride);
checkSingleToken("requires"_s, TokenType::KeywordRequires);
checkSingleToken("return"_s, TokenType::KeywordReturn);
checkSingleToken("struct"_s, TokenType::KeywordStruct);
checkSingleToken("switch"_s, TokenType::KeywordSwitch);
checkSingleToken("true"_s, TokenType::KeywordTrue);
checkSingleToken("var"_s, TokenType::KeywordVar);
checkSingleToken("while"_s, TokenType::KeywordWhile);
}
TEST(WGSLLexerTests, SpecialTokens)
{
using WGSL::TokenType;
checkSingleToken("->"_s, TokenType::Arrow);
checkSingleToken("@"_s, TokenType::Attribute);
checkSingleToken("!"_s, TokenType::Bang);
checkSingleToken("!="_s, TokenType::BangEq);
checkSingleToken("{"_s, TokenType::BraceLeft);
checkSingleToken("}"_s, TokenType::BraceRight);
checkSingleToken("["_s, TokenType::BracketLeft);
checkSingleToken("]"_s, TokenType::BracketRight);
checkSingleToken(":"_s, TokenType::Colon);
checkSingleToken(","_s, TokenType::Comma);
checkSingleToken("="_s, TokenType::Equal);
checkSingleToken("=="_s, TokenType::EqEq);
checkSingleToken(">"_s, TokenType::Gt);
checkSingleToken(">="_s, TokenType::GtEq);
checkSingleToken(">>"_s, TokenType::GtGt);
checkSingleToken(">>="_s, TokenType::GtGtEq);
checkSingleToken("<"_s, TokenType::Lt);
checkSingleToken("<="_s, TokenType::LtEq);
checkSingleToken("<<"_s, TokenType::LtLt);
checkSingleToken("<<="_s, TokenType::LtLtEq);
checkSingleToken("-"_s, TokenType::Minus);
checkSingleToken("--"_s, TokenType::MinusMinus);
checkSingleToken("-="_s, TokenType::MinusEq);
checkSingleToken("%"_s, TokenType::Modulo);
checkSingleToken("%="_s, TokenType::ModuloEq);
checkSingleToken("."_s, TokenType::Period);
checkSingleToken("("_s, TokenType::ParenLeft);
checkSingleToken(")"_s, TokenType::ParenRight);
checkSingleToken(";"_s, TokenType::Semicolon);
checkSingleToken("/"_s, TokenType::Slash);
checkSingleToken("/="_s, TokenType::SlashEq);
checkSingleToken("*"_s, TokenType::Star);
checkSingleToken("*="_s, TokenType::StarEq);
checkSingleToken("+"_s, TokenType::Plus);
checkSingleToken("++"_s, TokenType::PlusPlus);
checkSingleToken("+="_s, TokenType::PlusEq);
checkSingleToken("&"_s, TokenType::And);
checkSingleToken("&&"_s, TokenType::AndAnd);
checkSingleToken("&="_s, TokenType::AndEq);
checkSingleToken("|"_s, TokenType::Or);
checkSingleToken("||"_s, TokenType::OrOr);
checkSingleToken("|="_s, TokenType::OrEq);
checkSingleToken("^"_s, TokenType::Xor);
checkSingleToken("^="_s, TokenType::XorEq);
checkSingleToken("~"_s, TokenType::Tilde);
checkSingleToken("_"_s, TokenType::Underbar);
}
TEST(WGSLLexerTests, ComputeShader)
{
TestLexer lexer(
"@block struct B {\n"
" a: i32,\n"
"}\n"
"\n"
"@group(0) @binding(0)\n"
"var<storage, read_write> x: B;\n"
"\n"
"@compute\n"
"fn main() {\n"
" x.a = 42;\n"
"}"_s);
unsigned lineNumber = 1;
// @block struct B {
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "block"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordStruct, lineNumber);
checkNextTokenIsIdentifier(lexer, "B"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BraceLeft, lineNumber);
// a: i32;
++lineNumber;
checkNextTokenIsIdentifier(lexer, "a"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Colon, lineNumber);
checkNextTokenIsIdentifier(lexer, "i32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
// }
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
// @group(0) @binding(0)
lineNumber += 2;
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "group"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "binding"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
// var<storage, read_write> x: B;
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::KeywordVar, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "storage"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsIdentifier(lexer, "read_write"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIsIdentifier(lexer, "x"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Colon, lineNumber);
checkNextTokenIsIdentifier(lexer, "B"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
// @compute
lineNumber += 2;
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "compute"_s, lineNumber);
// fn main() {
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::KeywordFn, lineNumber);
checkNextTokenIsIdentifier(lexer, "main"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BraceLeft, lineNumber);
// x.a = 42;
++lineNumber;
checkNextTokenIsIdentifier(lexer, "x"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Period, lineNumber);
checkNextTokenIsIdentifier(lexer, "a"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Equal, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 42, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
// }
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::EndOfFile, lineNumber);
}
TEST(WGSLLexerTests, GraphicsShader)
{
TestLexer lexer(
"@vertex\n"
"fn vertexShader(@location(0) x: vec4<f32>) -> @builtin(position) vec4<f32> {\n"
" return x;\n"
"}\n"
"\n"
"@fragment\n"
"fn fragmentShader() -> @location(0) vec4<f32> {\n"
" return vec4<f32>(0.4, 0.4, 0.8, 1.0);\n"
"}"_s);
unsigned lineNumber = 1;
// @vertex
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "vertex"_s, lineNumber);
++lineNumber;
// fn vertexShader(@location(0) x: vec4<f32>) -> @builtin(position) vec4<f32> {
checkNextTokenIs(lexer, WGSL::TokenType::KeywordFn, lineNumber);
checkNextTokenIsIdentifier(lexer, "vertexShader"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "location"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIsIdentifier(lexer, "x"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Colon, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Arrow, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "builtin"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIdentifier(lexer, "position"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BraceLeft, lineNumber);
// return x;
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::KeywordReturn, lineNumber);
checkNextTokenIsIdentifier(lexer, "x"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
// }
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
// @fragment
lineNumber += 2;
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "fragment"_s, lineNumber);
// fn fragmentShader() -> @location(0) vec4<f32> {
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::KeywordFn, lineNumber);
checkNextTokenIsIdentifier(lexer, "fragmentShader"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Arrow, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "location"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BraceLeft, lineNumber);
// return vec4<f32>(0.4, 0.4, 0.8, 1.0);
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::KeywordReturn, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.4, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.4, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.8, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 1.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
// }
++lineNumber;
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::EndOfFile, lineNumber);
}
TEST(WGSLLexerTests, TriangleVert)
{
TestLexer lexer(
"@vertex\n"
"fn main(\n"
" @builtin(vertex_index) VertexIndex : u32\n"
") -> @builtin(position) vec4<f32> {\n"
" var pos = array<vec2<f32>, 3>(\n"
" vec2<f32>(0.0, 0.5),\n"
" vec2<f32>(-0.5, -0.5),\n"
" vec2<f32>(0.5, -0.5)\n"
" );\n\n"
" return vec4<f32>(pos[VertexIndex] + vec2<f32>(0.5, 0.5), 0.0, 1.0);\n"
"}\n"_s);
unsigned lineNumber = 1;
// @vertex
checkNextTokenIs(lexer, WGSL::TokenType::Attribute, lineNumber);
checkNextTokenIsIdentifier(lexer, "vertex"_s, lineNumber);
++lineNumber;
// fn main(
checkNextTokenIs(lexer, WGSL::TokenType::KeywordFn, lineNumber);
checkNextTokenIsIdentifier(lexer, "main"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
++lineNumber;
// @builtin(vertex_index) VertexIndex : u32
checkNextTokensAreBuiltinAttr(lexer, "vertex_index"_s, lineNumber);
checkNextTokenIsIdentifier(lexer, "VertexIndex"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Colon, lineNumber);
checkNextTokenIsIdentifier(lexer, "u32"_s, lineNumber);
++lineNumber;
// ) -> @builtin(position) vec4<f32> {
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Arrow, lineNumber);
checkNextTokensAreBuiltinAttr(lexer, "position"_s, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BraceLeft, lineNumber);
++lineNumber;
// var pos = array<vec2<f32>, 3>(
checkNextTokenIs(lexer, WGSL::TokenType::KeywordVar, lineNumber);
checkNextTokenIsIdentifier(lexer, "pos"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Equal, lineNumber);
checkNextTokenIsIdentifier(lexer, "array"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsIntegerLiteral(lexer, WGSL::TokenType::IntegerLiteral, 3, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
++lineNumber;
// vec2<f32>(0.0, 0.5),
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
++lineNumber;
// vec2<f32>(-0.5, -0.5),
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
++lineNumber;
// vec2<f32>(0.5, -0.5)
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
++lineNumber;
// );
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
lineNumber += 2;
// return vec4<f32>(pos[VertexIndex] + vec2<f32>(0.5, 0.5), 0.0, 1.0);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordReturn, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsIdentifier(lexer, "pos"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BracketLeft, lineNumber);
checkNextTokenIsIdentifier(lexer, "VertexIndex"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::BracketRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Plus, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Lt, lineNumber);
checkNextTokenIsIdentifier(lexer, "f32"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Gt, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 0.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsFloatLiteral(lexer, WGSL::TokenType::AbstractFloatLiteral, 1.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
++lineNumber;
// }
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
}
}