blob: f35420d57d730ea1591e64ca3b96b0fef71db939 [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 {
static WGSL::Token checkSingleToken(const String& string, WGSL::TokenType type)
{
WGSL::Lexer<LChar> lexer(string);
WGSL::Token result = lexer.lex();
EXPECT_EQ(result.m_type, type);
return result;
}
static void checkSingleLiteral(const String& string, WGSL::TokenType type, double literalValue)
{
WGSL::Token result = checkSingleToken(string, type);
EXPECT_EQ(result.m_literalValue, literalValue);
}
template<typename T>
static WGSL::Token checkNextTokenIs(WGSL::Lexer<T>& lexer, WGSL::TokenType type, unsigned lineNumber)
{
WGSL::Token result = lexer.lex();
EXPECT_EQ(result.m_type, type);
EXPECT_EQ(result.m_span.m_line, lineNumber);
return result;
}
template<typename T>
static void checkNextTokenIsIdentifier(WGSL::Lexer<T>& lexer, const String& ident, unsigned lineNumber)
{
WGSL::Token result = checkNextTokenIs(lexer, WGSL::TokenType::Identifier, lineNumber);
EXPECT_EQ(result.m_ident, ident);
}
template<typename T>
static void checkNextTokenIsLiteral(WGSL::Lexer<T>& lexer, WGSL::TokenType type, double literalValue, unsigned lineNumber)
{
WGSL::Token result = checkNextTokenIs(lexer, type, lineNumber);
EXPECT_EQ(result.m_literalValue, literalValue);
}
template<typename T>
static void checkNextTokensAreBuiltinAttr(WGSL::Lexer<T>& 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, SingleTokens)
{
using WGSL::TokenType;
checkSingleToken(""_s, TokenType::EndOfFile);
checkSingleLiteral("1"_s, TokenType::IntegerLiteral, 1);
checkSingleLiteral("0"_s, TokenType::IntegerLiteral, 0);
checkSingleLiteral("142"_s, TokenType::IntegerLiteral, 142);
checkSingleLiteral("1.1"_s, TokenType::DecimalFloatLiteral, 1.1);
checkSingleLiteral("0.4"_s, TokenType::DecimalFloatLiteral, 0.4);
checkSingleLiteral("0123.456"_s, TokenType::DecimalFloatLiteral, 0123.456);
checkSingleToken("0123"_s, TokenType::Invalid);
checkSingleLiteral("0123."_s, TokenType::DecimalFloatLiteral, 123);
checkSingleLiteral(".456"_s, TokenType::DecimalFloatLiteral, 0.456);
checkSingleToken("."_s, TokenType::Period);
checkSingleLiteral("42f"_s, TokenType::DecimalFloatLiteral, 42);
checkSingleLiteral("42e0f"_s, TokenType::DecimalFloatLiteral, 42);
checkSingleLiteral("042e0f"_s, TokenType::DecimalFloatLiteral, 42);
checkSingleToken("042f"_s, TokenType::Invalid);
checkSingleLiteral("42e-3"_s, TokenType::DecimalFloatLiteral, 42e-3);
checkSingleLiteral("42e-a"_s, TokenType::IntegerLiteral, 42);
}
TEST(WGSLLexerTests, KeywordTokens)
{
using WGSL::TokenType;
checkSingleToken("array"_s, TokenType::KeywordArray);
checkSingleToken("fn"_s, TokenType::KeywordFn);
checkSingleToken("function"_s, TokenType::KeywordFunction);
checkSingleToken("private"_s, TokenType::KeywordPrivate);
checkSingleToken("read"_s, TokenType::KeywordRead);
checkSingleToken("read_write"_s, TokenType::KeywordReadWrite);
checkSingleToken("return"_s, TokenType::KeywordReturn);
checkSingleToken("storage"_s, TokenType::KeywordStorage);
checkSingleToken("struct"_s, TokenType::KeywordStruct);
checkSingleToken("uniform"_s, TokenType::KeywordUniform);
checkSingleToken("var"_s, TokenType::KeywordVar);
checkSingleToken("workgroup"_s, TokenType::KeywordWorkgroup);
checkSingleToken("write"_s, TokenType::KeywordWrite);
checkSingleToken("i32"_s, TokenType::KeywordI32);
checkSingleToken("u32"_s, TokenType::KeywordU32);
checkSingleToken("f32"_s, TokenType::KeywordF32);
checkSingleToken("bool"_s, TokenType::KeywordBool);
}
TEST(WGSLLexerTests, SpecialTokens)
{
using WGSL::TokenType;
checkSingleToken("->"_s, TokenType::Arrow);
checkSingleToken("@"_s, TokenType::Attribute);
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::GT);
checkSingleToken("<"_s, TokenType::LT);
checkSingleToken("-"_s, TokenType::Minus);
checkSingleToken("--"_s, TokenType::MinusMinus);
checkSingleToken("."_s, TokenType::Period);
checkSingleToken("("_s, TokenType::ParenLeft);
checkSingleToken(")"_s, TokenType::ParenRight);
checkSingleToken(";"_s, TokenType::Semicolon);
}
TEST(WGSLLexerTests, ComputeShader)
{
WGSL::Lexer<LChar> 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 = 0;
// @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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordI32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, 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);
checkNextTokenIsLiteral(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);
checkNextTokenIsLiteral(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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordStorage, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordReadWrite, 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);
checkNextTokenIsLiteral(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)
{
WGSL::Lexer<LChar> 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 = 0;
// @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);
checkNextTokenIsLiteral(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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, 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);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::IntegerLiteral, 0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::LT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::GT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.4, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.4, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.8, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 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)
{
WGSL::Lexer<LChar> 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], 0.0, 1.0);\n"
"}\n"_s);
unsigned lineNumber = 0;
// @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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordU32, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordArray, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::LT, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec2"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::LT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::GT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::GT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::GT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 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);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::GT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenLeft, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.5, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Minus, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 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], 0.0, 1.0);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordReturn, lineNumber);
checkNextTokenIsIdentifier(lexer, "vec4"_s, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::LT, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::KeywordF32, 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::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 0.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Comma, lineNumber);
checkNextTokenIsLiteral(lexer, WGSL::TokenType::DecimalFloatLiteral, 1.0, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::ParenRight, lineNumber);
checkNextTokenIs(lexer, WGSL::TokenType::Semicolon, lineNumber);
++lineNumber;
// }
checkNextTokenIs(lexer, WGSL::TokenType::BraceRight, lineNumber);
}
}