wgsl-parser 0.5.0

A zero-copy recursive-descent parser for WebGPU shading language
Documentation
use snapshot::{begin_snapshots, snapshot, snapshot_test};

begin_snapshots!();

macro_rules! join {
	($char:literal, $input:literal) => {
		$input
	};
	($char:literal, $input:tt) => {
		stringify!($input)
	};
	($char:literal, $input:literal $($remaining:tt)+) => {
		concat!($input, $char, join!($char, $($remaining)+))
	};
	($char:literal, $input:tt $($remaining:tt)+) => {
		concat!(stringify!($input), $char, join!($char, $($remaining)+))
	};
}

macro_rules! tokens {
	($($input:tt),+ $(,)?) => {{
		use ::itertools::Itertools;
		use $crate::gramatika::Lexer as _;

		let input = ::gramatika::arcstr::literal_substr!(join!("\n", $($input)+));
		let tokens = $crate::token::Lexer::new(input).scan();

		tokens.iter()
			.map(|token| ::std::format!("{token:?}"))
			.join("\n")
	}};
}

#[snapshot_test]
fn two_char_tokens() {
	snapshot!("{}", tokens![
		"&&", "||", "--", "++", "==", ">>", "<<", "!=", "<=", ">=", "->", "::",
	]);
}

#[snapshot_test]
fn one_char_tokens() {
	#[rustfmt::skip]
	snapshot!("{}", tokens![
		// Operator
		"&", "|", "-", "+", "=", ">", "<", "!", "%", "*", "/", "~", "^",
		// Brace
		"[", "]", "{", "}", "(", ")",
		// Punct
		":", ",", ".", ";",
	]);
}

#[snapshot_test]
fn unrecognized_input() {
	snapshot!("{}", tokens![
		"'", "$", "—", "°", "é", "😬", "🤷", "会", "英"
	]);
}

#[snapshot_test]
fn decimal_float_literal() {
	snapshot!("{}", tokens![
		"42.42",
		".42",
		"42.",
		"42.42e10",
		"42.42e-10",
		"42.42e+10",
		"42.e10",
		"42.e-10",
		"42.e+10",
		".42e10",
		".42e-10",
		".42e+10",
	]);
}

#[snapshot_test]
fn hex_float_literal() {
	snapshot!("{}", tokens![
		"0x42a.42",
		"0x.42a",
		"0x42a.",
		"0x42a.42p10",
		"0x42a.42p-10",
		"0x42a.42p+10",
		"0x42a.p10",
		"0x42a.p-10",
		"0x42a.p+10",
		"0x.42Ap10",
		"0x.42Ap-10",
		"0x.42Ap+10",
		"0x42Ap10",
		"0x42Ap-10",
		"0x42Ap+10",
	]);
}

#[rustfmt::skip]
#[snapshot_test]
fn int_literal() {
	snapshot!("{}", tokens![
		"0",
		"42",
		"0x42a",
		"0u",
		"0i",
		"42u",
		"42i",
		"0x42Au",
		"0x42Ai",
	]);
}

#[snapshot_test]
fn path() {
	snapshot!("{}", tokens![
		r#""foo""#,
		r#""./foo""#,
		r#""./foo/bar/baz/foo-bar""#,
		r#""./My Documents/Lorem Ipsum""#,
	]);
}

#[snapshot_test]
fn types() {
	snapshot!("{}", tokens![
		"array",
		"atomic",
		"bool",
		"f32",
		"i32",
		"u32",
		"mat2x2",
		"mat2x3",
		"mat2x4",
		"mat3x2",
		"mat3x3",
		"mat3x4",
		"mat4x2",
		"mat4x3",
		"mat4x4",
		"ptr",
		"sampler",
		"sampler_comparison",
		"vec2",
		"vec3",
		"vec4",
		"texture_multisampled_2d",
		"texture_external",
		"texture_depth_2d",
		"texture_depth_2d_array",
		"texture_depth_cube",
		"texture_depth_cube_array",
		"texture_1d",
		"texture_2d",
		"texture_2d_array",
		"texture_3d",
		"texture_cube",
		"texture_cube_array",
		"texture_storage_1d",
		"texture_storage_2d",
		"texture_storage_2d_array",
		"texture_storage_3d",
	]);
}

#[snapshot_test]
fn keywords() {
	snapshot!("{}", tokens![
		"fn",
		"let",
		"struct",
		"alias",
		"var",
		"const",
		"export",
		"function",
		"private",
		"read",
		"read_write",
		"storage",
		"uniform",
		"workgroup",
		"write",
		"break",
		"case",
		"continue",
		"continuing",
		"default",
		"else",
		"fallthrough",
		"for",
		"if",
		"loop",
		"return",
		"switch",
		"from",
		"true",
		"false",
		"bitcast",
		"discard",
		"enable",
		"import",
	]);
}

#[snapshot_test]
fn identifiers() {
	snapshot!("{}", tokens![
		"foo",
		"bar",
		"baz",
		"foo_bar",
		"foo2",
		"loremIpsumDolor",
		"SitAmet",
		"LOUD_NOISES",
		"__private",
		"_",
	]);
}

#[snapshot_test]
fn kitchen_sink() {
	// TODO: Are these really necessary anymore?
	snapshot!("{}", tokens!["var<uniform> uniforms: Uniforms;"]);
	snapshot!("{}", tokens![
		"@group(0) @binding(0) var t_diffuse: texture_2d<f32>;"
	]);
	snapshot!("{}", tokens![
		r#"
		@group(0) @binding(0)
		var t_diffuse: texture_2d<f32>;
	"#
	]);
}