Skip to main content

besl/
parser.rs

1//! Parses BESL tokens into syntax nodes that preserve the source structure.
2//!
3//! # Example shader
4//!
5//! ```glsl
6//! Light: struct {
7//!     position: vec3,
8//!     color: vec3,
9//! }
10//!
11//! main: fn () -> void {
12//!     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
13//! }
14//! ```
15//!
16//! Use [`crate::parse`] as the entry point. The parser records cross-references by name.
17//! The [`crate::lexer`] module resolves those names later.
18
19use crate::tokenizer;
20
21/// A shared syntax node in a parsed BESL tree.
22pub type NodeReference<'a> = &'a Node<'a>;
23
24/// The `TypeName` enum preserves type structure while the parser still borrows source text.
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum TypeName<'a> {
27	Named(&'a str),
28	Array { element: Box<TypeName<'a>>, count: u32 },
29}
30
31impl std::fmt::Display for TypeName<'_> {
32	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33		match self {
34			Self::Named(name) => f.write_str(name),
35			Self::Array { element, count } => write!(f, "{element}[{count}]"),
36		}
37	}
38}
39
40/// A weak syntax-node reference used to avoid ownership cycles.
41pub(super) fn parse<'i, 'a: 'i>(tokens: &'i tokenizer::Tokens<'a>) -> Result<Node<'a>, ParsingFailReasons> {
42	let mut iterator = tokens.tokens.iter();
43
44	let parsers = [
45		parse_push_constant,
46		parse_struct,
47		parse_function,
48		parse_macro,
49		parse_const,
50		parse_descriptor,
51		parse_shader_interface_declaration,
52		parse_member,
53	];
54
55	let mut children: Vec<Node<'a>> = Vec::with_capacity(64);
56
57	loop {
58		let (expression, iter) = execute_parsers(parsers.as_slice(), iterator)?;
59
60		children.push(expression);
61
62		iterator = iter;
63
64		if iterator.len() == 0 {
65			break;
66		}
67	}
68
69	Ok(make_scope("root", children))
70}
71
72use std::borrow::Cow;
73use std::num::{NonZeroU32, NonZeroUsize};
74
75#[derive(Clone, Debug)]
76pub struct Node<'a> {
77	pub(crate) node: Nodes<'a>,
78}
79
80impl<'a> Node<'a> {
81	pub fn root() -> Node<'a> {
82		make_scope("root", Vec::new())
83	}
84
85	pub fn root_with_children(children: Vec<Node<'a>>) -> Node<'a> {
86		make_scope("root", children)
87	}
88
89	pub fn scope(name: &'a str, children: Vec<Node<'a>>) -> Node<'a> {
90		make_scope(name, children)
91	}
92
93	pub fn r#struct(name: &'a str, fields: Vec<Node<'a>>) -> Node<'a> {
94		make_struct(name, fields)
95	}
96
97	pub fn member(name: &'a str, r#type: &'_ str) -> Node<'a> {
98		make_member(name, r#type)
99	}
100
101	pub fn member_expression(name: impl Into<Cow<'a, str>>) -> Node<'a> {
102		Node {
103			node: Nodes::Expression(Expressions::Member { name: name.into() }),
104		}
105	}
106
107	pub fn function(name: &'a str, params: Vec<Node<'a>>, return_type: &'a str, statements: Vec<Node<'a>>) -> Node<'a> {
108		make_function(name, params, return_type, statements)
109	}
110
111	pub fn conditional(condition: Node<'a>, statements: Vec<Node<'a>>) -> Node<'a> {
112		Node {
113			node: Nodes::Conditional {
114				condition: Box::new(condition),
115				statements,
116			},
117		}
118	}
119
120	pub fn for_loop(initializer: Node<'a>, condition: Node<'a>, update: Node<'a>, statements: Vec<Node<'a>>) -> Node<'a> {
121		Node {
122			node: Nodes::ForLoop {
123				initializer: Box::new(initializer),
124				condition: Box::new(condition),
125				update: Box::new(update),
126				statements,
127			},
128		}
129	}
130
131	pub fn main_function(statements: Vec<Node<'a>>) -> Node<'a> {
132		make_function("main", Vec::new(), "void", statements)
133	}
134
135	pub fn binding(name: &'a str, r#type: Node<'a>, slot: u32, read: bool, write: bool) -> Node<'a> {
136		Self::binding_with_count(name, r#type, slot, read, write, None)
137	}
138
139	fn binding_with_count(
140		name: &'a str,
141		r#type: Node<'a>,
142		slot: u32,
143		read: bool,
144		write: bool,
145		count: Option<NonZeroUsize>,
146	) -> Node<'a> {
147		Node {
148			node: Nodes::Binding {
149				name,
150				r#type: Box::new(r#type),
151				slot,
152				read,
153				write,
154				count,
155			},
156		}
157	}
158
159	pub fn binding_array(name: &'a str, r#type: Node<'a>, slot: u32, read: bool, write: bool, count: u32) -> Node<'a> {
160		let count = NonZeroUsize::new(count as usize).expect(
161			"Invalid binding array count. The most likely cause is that a resource array was declared with zero elements.",
162		);
163		Self::binding_with_count(name, r#type, slot, read, write, Some(count))
164	}
165
166	pub fn specialization(name: &'a str, r#type: &'a str) -> Node<'a> {
167		Node {
168			node: Nodes::Specialization { name, r#type },
169		}
170	}
171
172	pub fn buffer(name: &'a str, members: Vec<Node<'a>>) -> Node<'a> {
173		Node {
174			node: Nodes::Type { name, members },
175		}
176	}
177
178	pub fn image(format: &'a str) -> Node<'a> {
179		Node {
180			node: Nodes::Image { format },
181		}
182	}
183
184	pub fn push_constant(members: Vec<Node<'a>>) -> Node<'a> {
185		Node {
186			node: Nodes::PushConstant { members },
187		}
188	}
189
190	pub fn combined_image_sampler() -> Node<'a> {
191		Node {
192			node: Nodes::CombinedImageSampler { format: "" },
193		}
194	}
195
196	pub fn combined_array_image_sampler() -> Node<'a> {
197		Node {
198			node: Nodes::CombinedImageSampler {
199				format: "ArrayTexture2D",
200			},
201		}
202	}
203
204	pub fn r#macro(name: &'a str, body: Node<'a>) -> Node<'a> {
205		Node {
206			node: Nodes::Expression(Expressions::Macro {
207				name,
208				body: Box::new(body),
209			}),
210		}
211	}
212
213	pub fn sentence(expressions: Vec<Node<'a>>) -> Node<'a> {
214		Node {
215			node: Nodes::Expression(Expressions::Expression(expressions)),
216		}
217	}
218
219	pub fn expression(elements: Vec<Node<'a>>) -> Node<'a> {
220		Self::sentence(elements)
221	}
222
223	pub fn accessor(left: Node<'a>, right: Node<'a>) -> Node<'a> {
224		Node {
225			node: Nodes::Expression(Expressions::Accessor {
226				left: Box::new(left),
227				right: Box::new(right),
228			}),
229		}
230	}
231
232	pub fn call(name: &'a str, parameters: Vec<Node<'a>>) -> Node<'a> {
233		Node {
234			node: Nodes::Expression(Expressions::Call {
235				name: TypeName::Named(name),
236				parameters,
237			}),
238		}
239	}
240
241	pub fn operator(name: &'a str, left: Node<'a>, right: Node<'a>) -> Node<'a> {
242		Node {
243			node: Nodes::Expression(Expressions::Operator {
244				name,
245				left: Box::new(left),
246				right: Box::new(right),
247			}),
248		}
249	}
250
251	pub fn assignment(left: Node<'a>, right: Node<'a>) -> Node<'a> {
252		Self::operator("=", left, right)
253	}
254
255	pub fn variable_declaration(name: &'a str, r#type: &'a str) -> Node<'a> {
256		Node {
257			node: Nodes::Expression(Expressions::VariableDeclaration {
258				name,
259				r#type: TypeName::Named(r#type),
260			}),
261		}
262	}
263
264	pub fn literal_expression(value: impl Into<Cow<'a, str>>) -> Node<'a> {
265		Node {
266			node: Nodes::Expression(Expressions::Literal { value: value.into() }),
267		}
268	}
269
270	pub fn return_value(value: Node<'a>) -> Node<'a> {
271		Node {
272			node: Nodes::Expression(Expressions::Return {
273				value: Some(Box::new(value)),
274			}),
275		}
276	}
277
278	pub fn return_void() -> Node<'a> {
279		Node {
280			node: Nodes::Expression(Expressions::Return { value: None }),
281		}
282	}
283
284	pub fn let_assignment(name: &'a str, r#type: &'a str, value: Node<'a>) -> Node<'a> {
285		Self::assignment(Self::variable_declaration(name, r#type), value)
286	}
287
288	pub fn member_assignment(name: &'a str, value: Node<'a>) -> Node<'a> {
289		Self::assignment(Self::member_expression(name), value)
290	}
291
292	pub fn glsl(code: impl Into<Cow<'a, str>>, input: &'a [&'a str], output: &'a [&'a str]) -> Node<'a> {
293		Self::raw_code(Some(code.into()), None, None, input, output)
294	}
295
296	pub fn hlsl(code: impl Into<Cow<'a, str>>, input: &'a [&'a str], output: &'a [&'a str]) -> Node<'a> {
297		Self::raw_code(None, Some(code.into()), None, input, output)
298	}
299
300	pub fn msl(code: impl Into<Cow<'a, str>>, input: &'a [&'a str], output: &'a [&'a str]) -> Node<'a> {
301		Self::raw_code(None, None, Some(code.into()), input, output)
302	}
303
304	/// Builds parser raw code with explicit backend sources and interface names.
305	pub fn raw_code(
306		glsl: Option<Cow<'a, str>>,
307		hlsl: Option<Cow<'a, str>>,
308		msl: Option<Cow<'a, str>>,
309		input: &'a [&'a str],
310		output: &'a [&'a str],
311	) -> Node<'a> {
312		Node {
313			node: Nodes::RawCode {
314				glsl,
315				hlsl,
316				msl,
317				input,
318				output,
319			},
320		}
321	}
322
323	pub fn literal(name: &'a str, body: Node<'a>) -> Node<'a> {
324		Node {
325			node: Nodes::Literal {
326				name,
327				body: Box::new(body),
328			},
329		}
330	}
331
332	pub fn input(name: &'a str, format: &'a str, location: u8) -> Node<'a> {
333		Node {
334			node: Nodes::Input { name, format, location },
335		}
336	}
337
338	pub fn output(name: &'a str, format: &'a str, location: u8) -> Node<'a> {
339		Self::output_with_count(name, format, location, None)
340	}
341
342	fn output_with_count(name: &'a str, format: &'a str, location: u8, count: Option<NonZeroUsize>) -> Node<'a> {
343		Node {
344			node: Nodes::Output {
345				name,
346				format,
347				location,
348				count,
349			},
350		}
351	}
352
353	pub fn output_array(name: &'a str, format: &'a str, location: u8, count: u32) -> Node<'a> {
354		Self::output_with_count(name, format, location, NonZeroUsize::new(count as usize))
355	}
356
357	pub fn task_payload(name: &'a str, format: &'a str, count: u32) -> Node<'a> {
358		let count = NonZeroUsize::new(count as usize).expect(
359			"Invalid task-payload count. The most likely cause is that a task-payload array was declared with zero elements.",
360		);
361		Node {
362			node: Nodes::TaskPayload { name, format, count },
363		}
364	}
365
366	pub fn workgroup(name: &'a str, format: &'a str) -> Node<'a> {
367		Node {
368			node: Nodes::Workgroup { name, format },
369		}
370	}
371
372	pub fn intrinsic(name: &'a str, parameters: Node<'a>, body: Node<'a>, r#return: &'a str) -> Node<'a> {
373		Node {
374			node: Nodes::Intrinsic {
375				name,
376				elements: vec![parameters, body],
377				r#return,
378			},
379		}
380	}
381
382	pub fn null() -> Node<'a> {
383		Node { node: Nodes::Null }
384	}
385
386	pub fn parameter(name: &'a str, r#type: &'a str) -> Node<'a> {
387		Node {
388			node: Nodes::Parameter { name, r#type },
389		}
390	}
391
392	pub fn constant(name: &'a str, r#type: &'a str, value: Node<'a>) -> Node<'a> {
393		Self::constant_with_type(name, TypeName::Named(r#type), value)
394	}
395
396	/// Builds a constant node while preserving the parsed type structure.
397	fn constant_with_type(name: &'a str, r#type: TypeName<'a>, value: Node<'a>) -> Node<'a> {
398		Node {
399			node: Nodes::Const {
400				name,
401				r#type,
402				value: Box::new(value),
403			},
404		}
405	}
406
407	pub fn name(&self) -> Option<&'a str> {
408		match &self.node {
409			Nodes::Scope { name, .. } => Some(name),
410			Nodes::Struct { name, .. } => Some(name),
411			Nodes::Member { name, .. } => Some(name),
412			Nodes::Function { name, .. } => Some(name),
413			Nodes::Conditional { .. } | Nodes::ForLoop { .. } => None,
414			Nodes::Binding { name, .. } => Some(name),
415			Nodes::Descriptor { name, .. } => Some(name),
416			Nodes::Specialization { name, .. } => Some(name),
417			Nodes::Type { name, .. } => Some(name),
418			Nodes::Image { .. } => None,
419			Nodes::CombinedImageSampler { .. } => None,
420			Nodes::Expression(_) => None,
421			Nodes::RawCode { .. } => None,
422			Nodes::Intrinsic { name, .. } => Some(name),
423			Nodes::Literal { name, .. } => Some(name),
424			Nodes::Parameter { name, .. } => Some(name),
425			Nodes::PushConstant { .. } => None,
426			Nodes::Input { name, .. }
427			| Nodes::Output { name, .. }
428			| Nodes::TaskPayload { name, .. }
429			| Nodes::Workgroup { name, .. } => Some(name),
430			Nodes::Const { name, .. } => Some(name),
431			Nodes::Null => None,
432		}
433	}
434
435	pub fn node_mut(&mut self) -> &mut Nodes<'a> {
436		// TODO: maybe do not expose nodes
437		&mut self.node
438	}
439
440	pub fn node(&self) -> &Nodes<'a> {
441		&self.node
442	}
443
444	pub fn get_mut(&mut self, name: &str) -> Option<&mut Node<'a>> {
445		match &mut self.node {
446			Nodes::Scope { children, .. } => children.iter_mut().find(|n| n.name() == Some(name)),
447			_ => None,
448		}
449	}
450
451	pub fn add(&mut self, children: Vec<Node<'a>>) {
452		match &mut self.node {
453			Nodes::Scope { children: c, .. } => {
454				// Extend from the beginning of the vector
455				c.extend(children);
456			}
457			_ => {
458				println!("Tried to add children to a non-scope node.");
459			}
460		}
461	}
462
463	pub(crate) fn sort(&mut self) {
464		// Place main function node at the end
465
466		if let Nodes::Scope { children, .. } = &mut self.node {
467			// Only sort scopes
468			// Place main function node at the end
469			children.sort_by(|a, b| {
470				if a.name() == Some("main") {
471					std::cmp::Ordering::Greater
472				} else if b.name() == Some("main") {
473					std::cmp::Ordering::Less
474				} else {
475					std::cmp::Ordering::Equal
476				}
477			});
478			children.iter_mut().for_each(|n| n.sort()); // Recursively sort children
479		}
480	}
481}
482
483#[derive(Clone, Debug)]
484pub enum Nodes<'a> {
485	/// A placeholder for syntax that does not yet have a specialized node.
486	Null,
487	/// A named group of BESL declarations, similar to a Rust module.
488	Scope {
489		/// The name used for imports and namespaces.
490		name: &'a str,
491		children: Vec<Node<'a>>,
492	},
493	/// A struct declaration and its fields.
494	Struct {
495		name: &'a str,
496		fields: Vec<Node<'a>>,
497	},
498	/// A field declared in a struct.
499	Member {
500		name: &'a str,
501		r#type: String,
502	},
503	/// A function declaration and body.
504	Function {
505		name: &'a str,
506		params: Vec<Node<'a>>,
507		return_type: &'a str,
508		statements: Vec<Node<'a>>,
509	},
510	Conditional {
511		condition: Box<Node<'a>>,
512		statements: Vec<Node<'a>>,
513	},
514	ForLoop {
515		initializer: Box<Node<'a>>,
516		condition: Box<Node<'a>>,
517		update: Box<Node<'a>>,
518		statements: Vec<Node<'a>>,
519	},
520	/// A shader resource binding declaration.
521	Binding {
522		name: &'a str,
523		r#type: Box<Node<'a>>,
524		slot: u32,
525		read: bool,
526		write: bool,
527		count: Option<NonZeroUsize>,
528	},
529	/// A flat resource descriptor declared directly in BESL source.
530	Descriptor {
531		name: &'a str,
532		resource_type: &'a str,
533		format: Option<&'a str>,
534		slot: u32,
535		read: bool,
536		write: bool,
537		count: Option<NonZeroU32>,
538	},
539	/// A constant selected when the application creates a pipeline.
540	Specialization {
541		name: &'a str,
542		r#type: &'a str,
543	},
544	/// A small constant buffer updated during rendering.
545	PushConstant {
546		members: Vec<Node<'a>>,
547	},
548	/// An abstract type declaration, such as the declaration for `f32`.
549	Type {
550		name: &'a str,
551		members: Vec<Node<'a>>,
552	},
553	Image {
554		format: &'a str,
555	},
556	CombinedImageSampler {
557		format: &'a str,
558	},
559	Expression(Expressions<'a>),
560	RawCode {
561		glsl: Option<Cow<'a, str>>,
562		hlsl: Option<Cow<'a, str>>,
563		msl: Option<Cow<'a, str>>,
564		input: &'a [&'a str],
565		output: &'a [&'a str],
566	},
567	Intrinsic {
568		name: &'a str,
569		elements: Vec<Node<'a>>,
570		r#return: &'a str,
571	},
572	Input {
573		name: &'a str,
574		format: &'a str,
575		location: u8,
576	},
577	Output {
578		name: &'a str,
579		format: &'a str,
580		location: u8,
581		count: Option<NonZeroUsize>,
582	},
583	/// An array carried from a task shader invocation group to the mesh work it emits.
584	TaskPayload {
585		name: &'a str,
586		format: &'a str,
587		count: NonZeroUsize,
588	},
589	/// Storage shared by all invocations in one task or compute workgroup.
590	Workgroup {
591		name: &'a str,
592		format: &'a str,
593	},
594	Literal {
595		name: &'a str,
596		body: Box<Node<'a>>,
597	},
598	Parameter {
599		name: &'a str,
600		r#type: &'a str,
601	},
602	/// A named module-level value known at compile time.
603	Const {
604		name: &'a str,
605		r#type: TypeName<'a>,
606		value: Box<Node<'a>>,
607	},
608}
609
610#[derive(Clone, Debug)]
611pub enum Expressions<'a> {
612	Expression(Vec<Node<'a>>),
613	Accessor {
614		left: Box<Node<'a>>,
615		right: Box<Node<'a>>,
616	},
617	Member {
618		name: Cow<'a, str>,
619	},
620	Literal {
621		value: Cow<'a, str>,
622	},
623	Call {
624		name: TypeName<'a>,
625		parameters: Vec<Node<'a>>,
626	},
627	Operator {
628		name: &'a str,
629		left: Box<Node<'a>>,
630		right: Box<Node<'a>>,
631	},
632	VariableDeclaration {
633		name: &'a str,
634		r#type: TypeName<'a>,
635	},
636	RawCode {
637		glsl: Option<&'a str>,
638		hlsl: Option<&'a str>,
639		msl: Option<&'a str>,
640		input: &'a [&'a str],
641		output: &'a [&'a str],
642	},
643	Macro {
644		name: &'a str,
645		body: Box<Node<'a>>,
646	},
647	Return {
648		value: Option<Box<Node<'a>>>,
649	},
650	Continue,
651}
652
653#[derive(Clone, Debug)]
654pub(super) enum Atoms<'a> {
655	Keyword,
656	Continue,
657	Accessor,
658	GroupedExpression(Vec<Atoms<'a>>),
659	Member {
660		name: &'a str,
661	},
662	Literal {
663		value: &'a str,
664	},
665	FunctionCall {
666		name: TypeName<'a>,
667		parameters: Vec<Vec<Atoms<'a>>>,
668	},
669	Operator {
670		name: &'a str,
671	},
672	VariableDeclaration {
673		name: &'a str,
674		r#type: TypeName<'a>,
675	},
676}
677
678#[derive(Debug)]
679pub enum ParsingFailReasons {
680	/// The parser does not handle this type of syntax.
681	NotMine,
682	/// The parser started handling a sequence of tokens, but it encountered a syntax error.
683	BadSyntax {
684		message: String,
685	},
686	StreamEndedPrematurely,
687}
688
689impl std::fmt::Display for ParsingFailReasons {
690	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
691		match self {
692			ParsingFailReasons::NotMine => write!(f, "Parser cannot handle this syntax."),
693			ParsingFailReasons::BadSyntax { message } => write!(f, "Bad syntax: {}", message),
694			ParsingFailReasons::StreamEndedPrematurely => {
695				write!(f, "Token stream ended prematurely.")
696			}
697		}
698	}
699}
700
701fn make_scope<'a>(name: &'a str, children: Vec<Node<'a>>) -> Node<'a> {
702	Node {
703		node: Nodes::Scope { name, children },
704	}
705}
706
707fn make_member<'a>(name: &'a str, r#type: &'_ str) -> Node<'a> {
708	Node {
709		node: Nodes::Member {
710			name,
711			r#type: r#type.to_string(),
712		},
713	}
714}
715
716fn make_struct<'a>(name: &'a str, children: Vec<Node<'a>>) -> Node<'a> {
717	Node {
718		node: Nodes::Struct { name, fields: children },
719	}
720}
721
722fn make_function<'a>(name: &'a str, params: Vec<Node<'a>>, return_type: &'a str, statements: Vec<Node<'a>>) -> Node<'a> {
723	Node {
724		node: Nodes::Function {
725			name,
726			params,
727			return_type,
728			statements,
729		},
730	}
731}
732
733trait Precedence {
734	fn precedence(&self) -> u8;
735}
736
737impl Precedence for Atoms<'_> {
738	fn precedence(&self) -> u8 {
739		match self {
740			Atoms::Keyword => 0,
741			Atoms::Continue => 0,
742			Atoms::Accessor => 1,
743			Atoms::GroupedExpression { .. } => 0,
744			Atoms::Member { .. } => 0,
745			Atoms::Literal { .. } => 0,
746			Atoms::FunctionCall { .. } => 0,
747			Atoms::Operator { name } => match *name {
748				"=" => 8,
749				"||" => 7,
750				"&&" => 6,
751				"|" => 7,
752				"&" => 6,
753				"==" => 5,
754				"!=" => 5,
755				"<" => 5,
756				">" => 5,
757				"<=" => 5,
758				">=" => 5,
759				"<<" => 4,
760				">>" => 4,
761				"+" => 3,
762				"-" => 3,
763				"*" => 2,
764				"/" => 2,
765				"%" => 2,
766				_ => 0,
767			},
768			Atoms::VariableDeclaration { .. } => 0,
769		}
770	}
771}
772
773/// The result type returned by a syntax parser.
774type FeatureParserResult<'i, 'a> = Result<(Node<'a>, std::slice::Iter<'i, &'a str>), ParsingFailReasons>;
775
776/// A function that tries to parse a token sequence.
777type FeatureParser<'i, 'a> = fn(std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a>;
778
779type ExpressionParserResult<'i, 'a> = Result<(Vec<Atoms<'a>>, std::slice::Iter<'i, &'a str>), ParsingFailReasons>;
780type ExpressionParser<'i, 'a> = fn(std::slice::Iter<'i, &'a str>, Vec<Atoms<'a>>) -> ExpressionParserResult<'i, 'a>;
781
782/// Runs parsers in order until one accepts the token stream.
783fn execute_parsers<'i, 'a: 'i>(
784	parsers: &[FeatureParser<'i, 'a>],
785	mut iterator: std::slice::Iter<'i, &'a str>,
786) -> FeatureParserResult<'i, 'a> {
787	let mut error = None;
788
789	for parser in parsers {
790		match parser(iterator.clone()) {
791			Ok(r) => return Ok(r),
792			Err(ParsingFailReasons::NotMine) => {}
793			Err(other) => {
794				if error.is_none() {
795					error = Some(other);
796				}
797			}
798		}
799	}
800
801	if let Some(error) = error {
802		return Err(error);
803	}
804
805	Err(ParsingFailReasons::BadSyntax {
806		message: format!(
807			"Tried several parsers none could handle the syntax for statement: {}",
808			iterator.next().unwrap()
809		),
810	}) // No parser could handle this syntax.
811}
812
813/// Runs parsers in order and permits every parser to decline the syntax.
814fn try_execute_parsers<'i, 'a: 'i>(
815	parsers: &[FeatureParser<'i, 'a>],
816	iterator: std::slice::Iter<'i, &'a str>,
817) -> Option<FeatureParserResult<'i, 'a>> {
818	for parser in parsers {
819		if let Ok(r) = parser(iterator.clone()) {
820			return Some(Ok(r));
821		}
822	}
823
824	None
825}
826
827/// Runs parsers in order until one accepts the token stream.
828fn execute_expression_parsers<'i, 'a: 'i>(
829	parsers: &[ExpressionParser<'i, 'a>],
830	mut iterator: std::slice::Iter<'i, &'a str>,
831	expressions: Vec<Atoms<'a>>,
832) -> ExpressionParserResult<'i, 'a> {
833	let mut error = None;
834
835	for parser in parsers {
836		match parser(iterator.clone(), expressions.clone()) {
837			Ok(r) => return Ok(r),
838			Err(ParsingFailReasons::NotMine) => {}
839			Err(other) => {
840				if error.is_none() {
841					error = Some(other);
842				}
843			}
844		}
845	}
846
847	if let Some(error) = error {
848		return Err(error);
849	}
850
851	Err(ParsingFailReasons::BadSyntax {
852		message: format!(
853			"Tried several parsers none could handle the syntax for statement: {}",
854			iterator.next().unwrap()
855		),
856	}) // No parser could handle this syntax.
857}
858
859/// Runs parsers in order and permits every parser to decline the syntax.
860fn try_execute_expression_parsers<'i, 'a: 'i>(
861	parsers: &[ExpressionParser<'i, 'a>],
862	iterator: std::slice::Iter<'i, &'a str>,
863	expressions: Vec<Atoms<'a>>,
864) -> Option<ExpressionParserResult<'i, 'a>> {
865	for parser in parsers {
866		if let Ok(r) = parser(iterator.clone(), expressions.clone()) {
867			return Some(Ok(r));
868		}
869	}
870
871	None
872}
873
874fn is_identifier_char(c: char) -> bool {
875	// TODO: validate number at end of identifier
876	c.is_alphanumeric() || c == '_'
877}
878
879fn is_identifier(s: &str) -> bool {
880	if s == "struct" || s == "fn" || s == "let" || s == "return" || s == "const" {
881		// should not be a keyword
882		return false;
883	}
884	s.chars().all(is_identifier_char)
885}
886
887fn parse_const<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
888	let name = iterator.next_identifier()?;
889	iterator.next_str(":")?;
890	iterator.next_str("const")?;
891
892	let r#type = iterator.next_identifier().map_err(|e| match e {
893		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
894			message: format!("Expected to find a type for const {}.", name),
895		},
896		_ => e,
897	})?;
898	let (r#type, mut iterator) = parse_type_name(iterator, r#type)?;
899
900	iterator.next_str("=").map_err(|e| match e {
901		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
902			message: format!("Expected to find = after type for const {}.", name),
903		},
904		_ => e,
905	})?;
906
907	let parsers = vec![parse_function_call, parse_literal, parse_variable];
908	let (expressions, new_iterator) = execute_expression_parsers(&parsers, iterator, Vec::new())?;
909	iterator = new_iterator;
910
911	iterator.next_str(";").map_err(|e| match e {
912		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
913			message: format!("Expected to find ; after const {} value.", name),
914		},
915		_ => e,
916	})?;
917
918	fn atoms_to_node<'a>(atoms: &[Atoms<'a>]) -> Node<'a> {
919		let max_precedence_item = atoms.iter().enumerate().max_by_key(|(_, v)| v.precedence());
920
921		if let Some((i, e)) = max_precedence_item {
922			match e {
923				Atoms::Operator { name } => {
924					let left = atoms_to_node(&atoms[..i]);
925					let right = atoms_to_node(&atoms[i + 1..]);
926					Node {
927						node: Nodes::Expression(Expressions::Operator {
928							name,
929							left: Box::new(left),
930							right: Box::new(right),
931						}),
932					}
933				}
934				Atoms::FunctionCall { name, parameters } => {
935					let parameters = parameters.iter().map(|v| atoms_to_node(v)).collect::<Vec<_>>();
936					Node {
937						node: Nodes::Expression(Expressions::Call {
938							name: name.clone(),
939							parameters,
940						}),
941					}
942				}
943				Atoms::Literal { value } => Node {
944					node: Nodes::Expression(Expressions::Literal { value: (*value).into() }),
945				},
946				Atoms::Member { name } => Node {
947					node: Nodes::Expression(Expressions::Member { name: (*name).into() }),
948				},
949				_ => panic!("Unexpected atom in const expression"),
950			}
951		} else {
952			panic!("No atoms in const expression");
953		}
954	}
955
956	let value = atoms_to_node(&expressions);
957
958	Ok((Node::constant_with_type(name, r#type, value), iterator))
959}
960
961/// Parses a flat resource descriptor and preserves its source type name for semantic resolution.
962fn parse_descriptor<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
963	let name = iterator.next_identifier()?;
964	iterator.next_str(":")?;
965	iterator.next_str("descriptor")?;
966
967	let syntax_error = |message: String| ParsingFailReasons::BadSyntax { message };
968	iterator.next_str("<").map_err(|_| {
969		syntax_error(format!(
970			"Expected < after descriptor in resource {}. The most likely cause is that the descriptor arguments are missing.",
971			name
972		))
973	})?;
974	let resource_type = iterator.next_identifier().map_err(|_| {
975		syntax_error(format!(
976			"Expected a resource type in descriptor {}. The most likely cause is that the first descriptor argument is missing.",
977			name
978		))
979	})?;
980	let format = if iterator.clone().next().copied() == Some("<") {
981		iterator.next();
982		let format = iterator.next_identifier().map_err(|_| {
983			syntax_error(format!(
984				"Expected a storage image format in descriptor {}. The most likely cause is that the StorageImage format argument is missing.",
985				name
986			))
987		})?;
988		iterator.next_str(">").map_err(|_| {
989			syntax_error(format!(
990				"Expected > after storage image format in descriptor {}. The most likely cause is that the resource type arguments are malformed.",
991				name
992			))
993		})?;
994		if resource_type != "StorageImage" {
995			return Err(syntax_error(format!(
996				"Resource type {} cannot declare format `{}` in descriptor {}. The most likely cause is that a storage image format was attached to a non-StorageImage resource.",
997				resource_type, format, name
998			)));
999		}
1000		Some(format)
1001	} else {
1002		None
1003	};
1004	iterator.next_str(",").map_err(|_| {
1005		syntax_error(format!(
1006			"Expected , after resource type in descriptor {}. The most likely cause is that the descriptor arguments are malformed.",
1007			name
1008		))
1009	})?;
1010
1011	let slot = iterator
1012		.next()
1013		.ok_or_else(|| {
1014			syntax_error(format!(
1015				"Expected a slot in descriptor {}. The most likely cause is that the second descriptor argument is missing.",
1016				name
1017			))
1018		})?
1019		.parse::<u32>()
1020		.map_err(|_| {
1021			syntax_error(format!(
1022				"Invalid slot in descriptor {}. The most likely cause is that the slot is not a u32 literal.",
1023				name
1024			))
1025		})?;
1026	iterator.next_str(",").map_err(|_| {
1027		syntax_error(format!(
1028			"Expected , after slot in descriptor {}. The most likely cause is that the descriptor arguments are malformed.",
1029			name
1030		))
1031	})?;
1032
1033	let access = iterator.next().ok_or_else(|| {
1034		syntax_error(format!(
1035			"Expected an access mode in descriptor {}. The most likely cause is that the third descriptor argument is missing.",
1036			name
1037		))
1038	})?;
1039	let (read, write) = match *access {
1040		"read" => (true, false),
1041		"write" => (false, true),
1042		"read_write" => (true, true),
1043		_ => {
1044			return Err(syntax_error(format!(
1045				"Invalid access mode `{}` in descriptor {}. The most likely cause is that the access is not read, write, or read_write.",
1046				access, name
1047			)));
1048		}
1049	};
1050
1051	let count = if iterator.clone().next().copied() == Some(",") {
1052		iterator.next();
1053		let count = iterator
1054			.next()
1055			.ok_or_else(|| {
1056				syntax_error(format!(
1057					"Expected a resource count in descriptor {}. The most likely cause is that the fourth descriptor argument is missing.",
1058					name
1059				))
1060			})?
1061			.parse::<u32>()
1062			.map_err(|_| {
1063				syntax_error(format!(
1064					"Invalid resource count in descriptor {}. The most likely cause is that the count is not a u32 literal.",
1065					name
1066				))
1067			})?;
1068		Some(NonZeroU32::new(count).ok_or_else(|| {
1069			syntax_error(format!(
1070				"Invalid resource count in descriptor {}. The most likely cause is that the resource array was declared with zero elements.",
1071				name
1072			))
1073		})?)
1074	} else {
1075		None
1076	};
1077
1078	iterator.next_str(">").map_err(|_| {
1079		syntax_error(format!(
1080			"Expected > after descriptor {} arguments. The most likely cause is that the descriptor declaration is incomplete.",
1081			name
1082		))
1083	})?;
1084	iterator.next_str(";").map_err(|_| {
1085		syntax_error(format!(
1086			"Expected ; after descriptor {}. The most likely cause is that the declaration terminator is missing.",
1087			name
1088		))
1089	})?;
1090
1091	Ok((
1092		Node {
1093			node: Nodes::Descriptor {
1094				name,
1095				resource_type,
1096				format,
1097				slot,
1098				read,
1099				write,
1100				count,
1101			},
1102		},
1103		iterator,
1104	))
1105}
1106
1107/// Parses stage-interface storage declared directly in BESL source.
1108fn parse_shader_interface_declaration<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1109	let name = iterator.next_identifier()?;
1110	iterator.next_str(":")?;
1111	let declaration = iterator.next().copied().ok_or(ParsingFailReasons::StreamEndedPrematurely)?;
1112	if !matches!(declaration, "input" | "output" | "task_payload" | "workgroup") {
1113		return Err(ParsingFailReasons::NotMine);
1114	}
1115
1116	let syntax_error = |message: String| ParsingFailReasons::BadSyntax { message };
1117	iterator.next_str("<").map_err(|_| {
1118		syntax_error(format!(
1119			"Expected < after {declaration} in {name}. The most likely cause is that the declaration arguments are missing."
1120		))
1121	})?;
1122	let format = iterator.next_identifier().map_err(|_| {
1123		syntax_error(format!(
1124			"Expected a type in {declaration} {name}. The most likely cause is that the first declaration argument is missing."
1125		))
1126	})?;
1127
1128	let node = match declaration {
1129		"input" | "output" => {
1130			iterator.next_str(",").map_err(|_| {
1131				syntax_error(format!(
1132					"Expected , after the type in {declaration} {name}. The most likely cause is that the location is missing."
1133				))
1134			})?;
1135			let location = iterator
1136				.next()
1137				.ok_or_else(|| {
1138					syntax_error(format!(
1139						"Expected a location in {declaration} {name}. The most likely cause is that the second declaration argument is missing."
1140					))
1141				})?
1142				.parse::<u8>()
1143				.map_err(|_| {
1144					syntax_error(format!(
1145						"Invalid location in {declaration} {name}. The most likely cause is that the location is not a u8 literal."
1146					))
1147				})?;
1148
1149			if declaration == "input" {
1150				Node::input(name, format, location)
1151			} else if iterator.clone().next().copied() == Some(",") {
1152				iterator.next();
1153				let count = iterator
1154					.next()
1155					.ok_or_else(|| {
1156						syntax_error(format!(
1157							"Expected an element count in output {name}. The most likely cause is that the third declaration argument is missing."
1158						))
1159					})?
1160					.parse::<u32>()
1161					.map_err(|_| {
1162						syntax_error(format!(
1163							"Invalid element count in output {name}. The most likely cause is that the count is not a u32 literal."
1164						))
1165					})?;
1166				if count == 0 {
1167					return Err(syntax_error(format!(
1168						"Invalid element count in output {name}. The most likely cause is that an output array was declared with zero elements."
1169					)));
1170				}
1171				Node::output_array(name, format, location, count)
1172			} else {
1173				Node::output(name, format, location)
1174			}
1175		}
1176		"task_payload" => {
1177			iterator.next_str(",").map_err(|_| {
1178				syntax_error(format!(
1179					"Expected , after the type in task_payload {name}. The most likely cause is that the element count is missing."
1180				))
1181			})?;
1182			let count = iterator
1183				.next()
1184				.ok_or_else(|| {
1185					syntax_error(format!(
1186						"Expected an element count in task_payload {name}. The most likely cause is that the second declaration argument is missing."
1187					))
1188				})?
1189				.parse::<u32>()
1190				.map_err(|_| {
1191					syntax_error(format!(
1192						"Invalid element count in task_payload {name}. The most likely cause is that the count is not a u32 literal."
1193					))
1194				})?;
1195			if count == 0 {
1196				return Err(syntax_error(format!(
1197					"Invalid element count in task_payload {name}. The most likely cause is that a task-payload array was declared with zero elements."
1198				)));
1199			}
1200			Node::task_payload(name, format, count)
1201		}
1202		"workgroup" => Node::workgroup(name, format),
1203		_ => unreachable!("Shader interface declaration was validated above."),
1204	};
1205
1206	iterator.next_str(">").map_err(|_| {
1207		syntax_error(format!(
1208			"Expected > after {declaration} {name} arguments. The most likely cause is that the declaration is incomplete."
1209		))
1210	})?;
1211	iterator.next_str(";").map_err(|_| {
1212		syntax_error(format!(
1213			"Expected ; after {declaration} {name}. The most likely cause is that the declaration terminator is missing."
1214		))
1215	})?;
1216
1217	Ok((node, iterator))
1218}
1219
1220/// Parses the single push-constant block exposed to shader source as `push_constant`.
1221fn parse_push_constant<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1222	iterator.next_str("push_constant")?;
1223	iterator.next_str(":")?;
1224	iterator.next_str("push_constant")?;
1225	iterator.next_str("{").map_err(|_| ParsingFailReasons::BadSyntax {
1226		message: "Expected { after push_constant declaration.".to_string(),
1227	})?;
1228
1229	let mut members = Vec::new();
1230	loop {
1231		let Some(token) = iterator.next().copied() else {
1232			return Err(ParsingFailReasons::BadSyntax {
1233				message: "Push-constant declaration is missing a closing }.".to_string(),
1234			});
1235		};
1236		if token == "}" {
1237			break;
1238		}
1239		if token == "," {
1240			continue;
1241		}
1242
1243		let member_name = token;
1244		iterator.next_str(":").map_err(|_| ParsingFailReasons::BadSyntax {
1245			message: format!("Expected : after push-constant member {member_name}."),
1246		})?;
1247		let member_type = iterator.next_identifier().map_err(|_| ParsingFailReasons::BadSyntax {
1248			message: format!("Expected a type after push-constant member {member_name}."),
1249		})?;
1250		members.push(make_member(member_name, member_type));
1251	}
1252
1253	Ok((Node::push_constant(members), iterator))
1254}
1255
1256fn parse_member<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1257	let name = iterator.next_identifier()?;
1258	iterator.next_str(":")?;
1259	let mut r#type = iterator
1260		.next_identifier()
1261		.map_err(|e| match e {
1262			ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1263				message: format!("Expected to find type while parsing member {}.", name),
1264			},
1265			_ => e,
1266		})?
1267		.to_string();
1268
1269	if let Some(&&n) = iterator.clone().peekable().peek() {
1270		if n == "<" {
1271			if r#type == "descriptor" {
1272				return Err(ParsingFailReasons::BadSyntax {
1273					message: format!(
1274						"Invalid descriptor declaration for {name}. The most likely cause is that required slot or access arguments are missing."
1275					),
1276				});
1277			}
1278			iterator.next();
1279			r#type.push('<');
1280			let next = iterator.next().ok_or(ParsingFailReasons::BadSyntax {
1281				message: format!("Expected to find type while parsing generic argument for member {}", name),
1282			})?;
1283			r#type.push_str(next.as_ref());
1284			iterator.next();
1285			r#type.push('>');
1286		}
1287	}
1288
1289	let node = Node::member(name, &r#type);
1290
1291	iterator.next().ok_or(ParsingFailReasons::BadSyntax {
1292		message: "Expected semicolon".to_string(),
1293	})?; // Skip semicolon
1294
1295	Ok(((node), iterator))
1296}
1297
1298fn parse_macro<'i, 'a: 'i>(iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1299	let mut iter = iterator;
1300
1301	iter.next_str("#")?;
1302	iter.next_str("[")?;
1303	iter.next_identifier().map_err(|e| match e {
1304		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1305			message: "Expected to find macro name after #[.".to_string(),
1306		},
1307		_ => e,
1308	})?;
1309	iter.next_str("]").map_err(|e| match e {
1310		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1311			message: "Expected to find ] after macro name.".to_string(),
1312		},
1313		_ => e,
1314	})?;
1315
1316	Ok((make_scope("MACRO", vec![]), iter))
1317}
1318
1319fn parse_struct<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1320	let name = iterator.next_identifier()?;
1321	iterator.next_str(":")?;
1322	iterator.next_str("struct")?;
1323	iterator.next_str("{").map_err(|e| match e {
1324		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1325			message: format!("Expected to find {{ after struct {} declaration.", name),
1326		},
1327		_ => e,
1328	})?;
1329
1330	let mut fields = vec![];
1331
1332	while let Some(&v) = iterator.next() {
1333		if v == "}" {
1334			break;
1335		} else if v == "," {
1336			continue;
1337		}
1338
1339		iterator.next_str(":").map_err(|e| match e {
1340			ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1341				message: format!("Expected to find : after name for member {} in struct {}", v, name),
1342			},
1343			_ => e,
1344		})?;
1345
1346		let type_name = iterator.next_identifier().map_err(|e| match e {
1347			ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1348				message: format!("Expected to find a type name after : for member {} in struct {}", v, name),
1349			},
1350			_ => e,
1351		})?;
1352
1353		// See if is array type
1354		let type_name = if iterator.clone().peekable().peek().map(|v| v.as_ref()) == Some("[") {
1355			iterator.next();
1356			let count = iterator
1357				.next()
1358				.and_then(|v| v.parse::<u32>().ok())
1359				.ok_or(ParsingFailReasons::BadSyntax {
1360					message: format!("Expected to find a number after [ for member {} in struct {}", v, name),
1361				})?;
1362			iterator.next().unwrap();
1363			format!("{}[{}]", type_name, count)
1364		} else {
1365			type_name.to_string()
1366		};
1367
1368		fields.push(make_member(v, &type_name));
1369	}
1370
1371	let node = Node::r#struct(name, fields);
1372
1373	Ok((node, iterator))
1374}
1375
1376fn parse_var_decl<'i, 'a: 'i>(
1377	mut iterator: std::slice::Iter<'i, &'a str>,
1378	mut expressions: Vec<Atoms<'a>>,
1379) -> ExpressionParserResult<'i, 'a> {
1380	iterator.next_str("let")?;
1381	let variable_name = iterator.next_identifier()?;
1382	iterator.next_str(":")?;
1383	let variable_type = iterator.next_identifier().map_err(|e| match e {
1384		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1385			message: format!("Expected to find a type for variable {}", variable_name),
1386		},
1387		_ => e,
1388	})?;
1389	let (variable_type, iterator) = parse_type_name(iterator, variable_type)?;
1390
1391	expressions.push(Atoms::VariableDeclaration {
1392		name: variable_name,
1393		r#type: variable_type,
1394	});
1395
1396	let possible_following_expressions: Vec<ExpressionParser<'i, 'a>> = vec![parse_operator];
1397
1398	let expressions = execute_expression_parsers(&possible_following_expressions, iterator, expressions)?;
1399
1400	Ok(expressions)
1401}
1402
1403/// Parses a source-backed type name and all of its array suffixes.
1404fn parse_type_name<'i, 'a: 'i>(
1405	mut iterator: std::slice::Iter<'i, &'a str>,
1406	base_type: &'a str,
1407) -> Result<(TypeName<'a>, std::slice::Iter<'i, &'a str>), ParsingFailReasons> {
1408	let mut type_name = TypeName::Named(base_type);
1409
1410	while iterator.clone().peekable().peek().map(|token| token.as_ref()) == Some("[") {
1411		iterator.next_str("[")?;
1412		let count = iterator
1413			.next_is(|token| token.chars().all(|c| c.is_ascii_digit()))?
1414			.parse::<u32>()
1415			.map_err(|_| ParsingFailReasons::BadSyntax {
1416				message: format!("Invalid array count for type {}", type_name),
1417			})?;
1418		iterator.next_str("]")?;
1419
1420		type_name = TypeName::Array {
1421			element: Box::new(type_name),
1422			count,
1423		};
1424	}
1425
1426	Ok((type_name, iterator))
1427}
1428
1429fn parse_keywords<'i, 'a: 'i>(
1430	mut iterator: std::slice::Iter<'i, &'a str>,
1431	mut expressions: Vec<Atoms<'a>>,
1432) -> ExpressionParserResult<'i, 'a> {
1433	iterator.next_str("return")?;
1434
1435	expressions.push(Atoms::Keyword);
1436
1437	if **iterator
1438		.clone()
1439		.peekable()
1440		.peek()
1441		.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1442		== ";"
1443	{
1444		return Ok((expressions, iterator));
1445	}
1446
1447	try_execute_expression_parsers(&[parse_rvalue], iterator.clone(), expressions.clone())
1448		.unwrap_or(Ok((expressions, iterator)))
1449}
1450
1451fn parse_continue<'i, 'a: 'i>(
1452	mut iterator: std::slice::Iter<'i, &'a str>,
1453	mut expressions: Vec<Atoms<'a>>,
1454) -> ExpressionParserResult<'i, 'a> {
1455	iterator.next_str("continue")?;
1456	expressions.push(Atoms::Continue);
1457	Ok((expressions, iterator))
1458}
1459
1460fn parse_variable<'i, 'a: 'i>(
1461	mut iterator: std::slice::Iter<'i, &'a str>,
1462	mut expressions: Vec<Atoms<'a>>,
1463) -> ExpressionParserResult<'i, 'a> {
1464	let name = iterator.next_identifier()?;
1465
1466	expressions.push(Atoms::Member { name });
1467
1468	let lexers = vec![parse_operator, parse_accessor, parse_index_accessor];
1469
1470	try_execute_expression_parsers(&lexers, iterator.clone(), expressions.clone()).unwrap_or(Ok((expressions, iterator)))
1471}
1472
1473fn parse_accessor<'i, 'a: 'i>(
1474	mut iterator: std::slice::Iter<'i, &'a str>,
1475	mut expressions: Vec<Atoms<'a>>,
1476) -> ExpressionParserResult<'i, 'a> {
1477	let _ = iterator.next_str(".")?;
1478
1479	expressions.push(Atoms::Accessor);
1480
1481	let lexers: Vec<ExpressionParser<'i, 'a>> = vec![parse_variable];
1482
1483	execute_expression_parsers(&lexers, iterator, expressions)
1484}
1485
1486fn parse_index_accessor<'i, 'a: 'i>(
1487	mut iterator: std::slice::Iter<'i, &'a str>,
1488	mut expressions: Vec<Atoms<'a>>,
1489) -> ExpressionParserResult<'i, 'a> {
1490	let _ = iterator.next_str("[")?;
1491	expressions.push(Atoms::Accessor);
1492	let (inner_expressions, mut iterator) = execute_expression_parsers(&[parse_rvalue], iterator, Vec::new())?;
1493	expressions.push(Atoms::GroupedExpression(inner_expressions));
1494	iterator.next_str("]")?;
1495
1496	let lexers = vec![parse_operator, parse_accessor, parse_index_accessor];
1497	try_execute_expression_parsers(&lexers, iterator.clone(), expressions.clone()).unwrap_or(Ok((expressions, iterator)))
1498}
1499
1500fn is_literal(s: &str) -> bool {
1501	matches!(s, "true" | "false") || s.chars().all(|c| c.is_ascii_digit() || c == '.')
1502}
1503
1504fn parse_literal<'i, 'a: 'i>(
1505	mut iterator: std::slice::Iter<'i, &'a str>,
1506	mut expressions: Vec<Atoms<'a>>,
1507) -> ExpressionParserResult<'i, 'a> {
1508	let value = iterator.next_is(is_literal)?;
1509
1510	expressions.push(Atoms::Literal { value });
1511
1512	let possible_following_expressions = vec![parse_operator, parse_accessor, parse_index_accessor];
1513
1514	try_execute_expression_parsers(&possible_following_expressions, iterator.clone(), expressions.clone())
1515		.unwrap_or(Ok((expressions, iterator)))
1516}
1517
1518/// Parses a parenthesized sub-expression like `(a + b)`.
1519fn parse_grouped_expression<'i, 'a: 'i>(
1520	mut iterator: std::slice::Iter<'i, &'a str>,
1521	mut expressions: Vec<Atoms<'a>>,
1522) -> ExpressionParserResult<'i, 'a> {
1523	iterator.next_str("(")?;
1524
1525	// Parse the inner expression
1526	let (inner_expressions, mut inner_iterator) = execute_expression_parsers(&[parse_rvalue], iterator, Vec::new())?;
1527
1528	inner_iterator.next_str(")").map_err(|_| ParsingFailReasons::BadSyntax {
1529		message: "Expected closing ')' for grouped expression".to_string(),
1530	})?;
1531
1532	// Keep grouped expressions intact so later lowering can preserve precedence.
1533	expressions.push(Atoms::GroupedExpression(inner_expressions));
1534
1535	// Check for following expressions (operators, accessors, etc.)
1536	let possible_following_expressions = vec![parse_operator, parse_accessor, parse_index_accessor];
1537
1538	try_execute_expression_parsers(&possible_following_expressions, inner_iterator.clone(), expressions.clone())
1539		.unwrap_or(Ok((expressions, inner_iterator)))
1540}
1541
1542fn parse_rvalue<'i, 'a: 'i>(
1543	iterator: std::slice::Iter<'i, &'a str>,
1544	expressions: Vec<Atoms<'a>>,
1545) -> ExpressionParserResult<'i, 'a> {
1546	let parsers = vec![parse_function_call, parse_grouped_expression, parse_literal, parse_variable];
1547
1548	execute_expression_parsers(&parsers, iterator.clone(), expressions)
1549}
1550
1551fn parse_operator<'i, 'a: 'i>(
1552	mut iterator: std::slice::Iter<'i, &'a str>,
1553	mut expressions: Vec<Atoms<'a>>,
1554) -> ExpressionParserResult<'i, 'a> {
1555	let operator =
1556		iterator.next_is(|v| {
1557			v == "*"
1558				|| v == "+" || v == "-"
1559				|| v == "/" || v == "%"
1560				|| v == "=" || v == "<"
1561				|| v == ">" || v == "=="
1562				|| v == "!=" || v == "<="
1563				|| v == ">=" || v == "&&"
1564				|| v == "||" || v == "<<"
1565				|| v == ">>" || v == "&"
1566				|| v == "|"
1567		})?;
1568
1569	expressions.push(Atoms::Operator { name: operator });
1570
1571	let possible_following_expressions: Vec<ExpressionParser<'i, 'a>> = vec![parse_rvalue];
1572
1573	execute_expression_parsers(&possible_following_expressions, iterator, expressions)
1574}
1575
1576fn expression_atoms_to_node<'a>(atoms: &[Atoms<'a>]) -> Node<'a> {
1577	if matches!(atoms.first(), Some(Atoms::Keyword)) {
1578		return Node {
1579			node: Nodes::Expression(Expressions::Return {
1580				value: atoms
1581					.get(1..)
1582					.filter(|remaining| !remaining.is_empty())
1583					.map(|remaining| Box::new(expression_atoms_to_node(remaining))),
1584			}),
1585		};
1586	}
1587
1588	if matches!(atoms.first(), Some(Atoms::Continue)) {
1589		return Node {
1590			node: Nodes::Expression(Expressions::Continue),
1591		};
1592	}
1593
1594	let max_precedence_item = atoms.iter().enumerate().max_by_key(|(_, v)| v.precedence());
1595
1596	if let Some((i, e)) = max_precedence_item {
1597		match e {
1598			Atoms::Keyword => Node {
1599				node: Nodes::Expression(Expressions::Return { value: None }),
1600			},
1601			Atoms::Continue => Node {
1602				node: Nodes::Expression(Expressions::Continue),
1603			},
1604			Atoms::Operator { name } => {
1605				let left = expression_atoms_to_node(&atoms[..i]);
1606				let right = expression_atoms_to_node(&atoms[i + 1..]);
1607
1608				Node {
1609					node: Nodes::Expression(Expressions::Operator {
1610						name,
1611						left: Box::new(left),
1612						right: Box::new(right),
1613					}),
1614				}
1615			}
1616			Atoms::Accessor => {
1617				let left = expression_atoms_to_node(&atoms[..i]);
1618				let right = expression_atoms_to_node(&atoms[i + 1..]);
1619
1620				Node {
1621					node: Nodes::Expression(Expressions::Accessor {
1622						left: Box::new(left),
1623						right: Box::new(right),
1624					}),
1625				}
1626			}
1627			Atoms::GroupedExpression(inner) => Node::sentence(vec![expression_atoms_to_node(inner)]),
1628			Atoms::FunctionCall { name, parameters } => {
1629				let parameters = parameters.iter().map(|v| expression_atoms_to_node(v)).collect::<Vec<_>>();
1630
1631				Node {
1632					node: Nodes::Expression(Expressions::Call {
1633						name: name.clone(),
1634						parameters,
1635					}),
1636				}
1637			}
1638			Atoms::Literal { value } => Node {
1639				node: Nodes::Expression(Expressions::Literal { value: (*value).into() }),
1640			},
1641			Atoms::Member { name } => Node {
1642				node: Nodes::Expression(Expressions::Member { name: (*name).into() }),
1643			},
1644			Atoms::VariableDeclaration { name, r#type } => Node {
1645				node: Nodes::Expression(Expressions::VariableDeclaration {
1646					name,
1647					r#type: r#type.clone(),
1648				}),
1649			},
1650		}
1651	} else {
1652		panic!("No max precedence item");
1653	}
1654}
1655
1656fn parse_conditional<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1657	iterator.next_str("if")?;
1658	iterator.next_str("(")?;
1659
1660	let (condition_atoms, mut iterator) = execute_expression_parsers(&[parse_rvalue], iterator, Vec::new())?;
1661	let condition = expression_atoms_to_node(&condition_atoms);
1662
1663	iterator.next_str(")")?;
1664	iterator.next_str("{")?;
1665
1666	let mut statements = vec![];
1667	loop {
1668		if **iterator
1669			.clone()
1670			.peekable()
1671			.peek()
1672			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1673			== "}"
1674		{
1675			iterator.next();
1676			break;
1677		}
1678
1679		let (statement, new_iterator) = parse_statement(iterator)?;
1680		statements.push(statement);
1681		iterator = new_iterator;
1682	}
1683
1684	Ok((Node::conditional(condition, statements), iterator))
1685}
1686
1687fn parse_for_loop<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1688	iterator.next_str("for")?;
1689	iterator.next_str("(")?;
1690
1691	let statement_parsers = vec![
1692		parse_keywords,
1693		parse_continue,
1694		parse_var_decl,
1695		parse_function_call,
1696		parse_variable,
1697	];
1698	let (initializer_atoms, mut iterator) = execute_expression_parsers(&statement_parsers, iterator, Vec::new())?;
1699	let initializer = expression_atoms_to_node(&initializer_atoms);
1700
1701	iterator.next_str(";")?;
1702
1703	let (condition_atoms, mut iterator) = execute_expression_parsers(&[parse_rvalue], iterator, Vec::new())?;
1704	let condition = expression_atoms_to_node(&condition_atoms);
1705
1706	iterator.next_str(";")?;
1707
1708	let (update_atoms, mut iterator) = execute_expression_parsers(&statement_parsers, iterator, Vec::new())?;
1709	let update = expression_atoms_to_node(&update_atoms);
1710
1711	iterator.next_str(")")?;
1712	iterator.next_str("{")?;
1713
1714	let mut statements = vec![];
1715	loop {
1716		if **iterator
1717			.clone()
1718			.peekable()
1719			.peek()
1720			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1721			== "}"
1722		{
1723			iterator.next();
1724			break;
1725		}
1726
1727		let (statement, new_iterator) = parse_statement(iterator)?;
1728		statements.push(statement);
1729		iterator = new_iterator;
1730	}
1731
1732	Ok((Node::for_loop(initializer, condition, update, statements), iterator))
1733}
1734
1735fn parse_function_call<'i, 'a: 'i>(
1736	mut iterator: std::slice::Iter<'i, &'a str>,
1737	mut expressions: Vec<Atoms<'a>>,
1738) -> ExpressionParserResult<'i, 'a> {
1739	let function_name = iterator.next_identifier()?;
1740	let (function_name, mut iterator) = parse_type_name(iterator, function_name)?;
1741	iterator.next_str("(")?;
1742
1743	let mut parameters = vec![];
1744
1745	loop {
1746		let iter_before = iterator.clone();
1747
1748		if let Some(a) = try_execute_expression_parsers(&[parse_rvalue], iterator.clone(), Vec::new()) {
1749			let (expressions, new_iterator) = a?;
1750			parameters.push(expressions);
1751			iterator = new_iterator;
1752		}
1753
1754		// Check if iter is comma
1755		if **iterator
1756			.clone()
1757			.peekable()
1758			.peek()
1759			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1760			== ","
1761		{
1762			iterator.next();
1763		}
1764
1765		// check if iter is close brace
1766		if **iterator
1767			.clone()
1768			.peekable()
1769			.peek()
1770			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1771			== ")"
1772		{
1773			iterator.next();
1774			break;
1775		}
1776
1777		// Safety: if no progress was made, break to avoid infinite loop
1778		if iterator.len() == iter_before.len() {
1779			let token = iterator.clone().peekable().peek().copied().copied().unwrap_or("<eof>");
1780			return Err(ParsingFailReasons::BadSyntax {
1781				message: format!("Unexpected token '{}' in function call {}", token, function_name),
1782			});
1783		}
1784	}
1785
1786	expressions.push(Atoms::FunctionCall {
1787		name: function_name,
1788		parameters,
1789	});
1790
1791	let possible_following_expressions = vec![parse_operator, parse_accessor, parse_index_accessor];
1792
1793	try_execute_expression_parsers(&possible_following_expressions, iterator.clone(), expressions.clone())
1794		.unwrap_or(Ok((expressions, iterator)))
1795}
1796
1797fn parse_statement<'i, 'a: 'i>(iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1798	if let Some(result) = try_execute_parsers(&[parse_conditional], iterator.clone()) {
1799		return result;
1800	}
1801
1802	if let Some(result) = try_execute_parsers(&[parse_for_loop], iterator.clone()) {
1803		return result;
1804	}
1805
1806	let parsers = vec![
1807		parse_keywords,
1808		parse_continue,
1809		parse_var_decl,
1810		parse_function_call,
1811		parse_variable,
1812	];
1813
1814	let (expressions, mut iterator) = execute_expression_parsers(&parsers, iterator, Vec::new())?;
1815
1816	iterator.next_str(";")?; // Skip semicolon
1817
1818	Ok((expression_atoms_to_node(&expressions), iterator))
1819}
1820
1821fn parse_function<'i, 'a: 'i>(mut iterator: std::slice::Iter<'i, &'a str>) -> FeatureParserResult<'i, 'a> {
1822	let name = iterator.next_identifier()?;
1823
1824	iterator.next_str(":")?;
1825	iterator.next_str("fn")?;
1826	iterator.next_str("(")?;
1827
1828	let mut params = Vec::new();
1829	loop {
1830		if **iterator
1831			.clone()
1832			.peekable()
1833			.peek()
1834			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1835			== ")"
1836		{
1837			iterator.next();
1838			break;
1839		}
1840
1841		let param_name = iterator.next_identifier().map_err(|e| match e {
1842			ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1843				message: format!("Expected a parameter name for function {}.", name),
1844			},
1845			_ => e,
1846		})?;
1847		iterator.next_str(":")?;
1848		let param_type = iterator.next_identifier().map_err(|e| match e {
1849			ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1850				message: format!("Expected a parameter type for function {}.", name),
1851			},
1852			_ => e,
1853		})?;
1854		params.push(Node::parameter(param_name, param_type));
1855
1856		if **iterator
1857			.clone()
1858			.peekable()
1859			.peek()
1860			.ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1861			== ","
1862		{
1863			iterator.next();
1864		}
1865	}
1866	iterator.next_str("->")?;
1867
1868	let return_type = iterator.next_identifier().map_err(|e| match e {
1869		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1870			message: format!("Expected a return type for function {} declaration.", name),
1871		},
1872		_ => e,
1873	})?;
1874
1875	iterator.next_str("{").map_err(|e| match e {
1876		ParsingFailReasons::NotMine => ParsingFailReasons::BadSyntax {
1877			message: format!("Expected a {{ after function {} declaration.", name),
1878		},
1879		_ => e,
1880	})?;
1881
1882	let mut statements = vec![];
1883
1884	loop {
1885		if let Some(Ok((expression, new_iterator))) = try_execute_parsers(&[parse_statement], iterator.clone()) {
1886			iterator = new_iterator;
1887
1888			statements.push(expression);
1889		} else {
1890			// A failed statement parser at EOF means the function body was truncated.
1891			let Some(token) = iterator.clone().next().copied() else {
1892				return Err(ParsingFailReasons::BadSyntax {
1893					message: format!(
1894						"Function `{}` is missing a closing `}}`. The source most likely ended before the function body was complete.",
1895						name
1896					),
1897				});
1898			};
1899
1900			if token == "}" {
1901				iterator.next();
1902				break;
1903			} else {
1904				return Err(ParsingFailReasons::BadSyntax {
1905					message: format!("Expected a }} after function {} declaration, found `{}`.", name, token),
1906				});
1907			}
1908		}
1909
1910		// check if iter is close brace
1911		if **iterator.clone().peekable().peek().ok_or(ParsingFailReasons::BadSyntax {
1912			message: "Expected a '}' after function body".to_string(),
1913		})? == "}"
1914		{
1915			iterator.next();
1916			break;
1917		}
1918	}
1919
1920	let node = Node::function(name, params, return_type, statements);
1921
1922	Ok((node, iterator))
1923}
1924
1925use std::ops::Index;
1926
1927impl<'a> Index<&str> for Node<'a> {
1928	type Output = Node<'a>;
1929
1930	fn index(&self, index: &str) -> &Self::Output {
1931		let child = match &self.node {
1932			Nodes::Scope { children, .. } => children.iter().find(|child| {
1933				matches!(
1934					child.node(),
1935					Nodes::Scope { .. }
1936						| Nodes::Struct { .. }
1937						| Nodes::Member { .. }
1938						| Nodes::Function { .. }
1939						| Nodes::Descriptor { .. }
1940						| Nodes::Input { .. }
1941						| Nodes::Output { .. }
1942						| Nodes::TaskPayload { .. }
1943						| Nodes::Workgroup { .. }
1944						| Nodes::Const { .. }
1945				) && child.name() == Some(index)
1946			}),
1947			Nodes::Struct { fields, .. } => fields
1948				.iter()
1949				.find(|field| matches!(field.node(), Nodes::Member { .. }) && field.name() == Some(index)),
1950			_ => panic!("Cannot search  in these"),
1951		};
1952
1953		child.unwrap_or_else(|| panic!("Not found"))
1954	}
1955}
1956
1957trait ParserIterator<'a> {
1958	fn next_is(&mut self, f: impl Fn(&'a str) -> bool) -> Result<&'a str, ParsingFailReasons>;
1959	fn next_str(&mut self, expected: &'a str) -> Result<&'a str, ParsingFailReasons>;
1960	fn next_identifier(&mut self) -> Result<&'a str, ParsingFailReasons>;
1961}
1962
1963impl<'i, 'a> ParserIterator<'a> for std::slice::Iter<'i, &'a str> {
1964	fn next_is(&mut self, f: impl Fn(&'a str) -> bool) -> Result<&'a str, ParsingFailReasons> {
1965		let token = self.next().ok_or(ParsingFailReasons::StreamEndedPrematurely)?;
1966		if f(token) {
1967			Ok(token)
1968		} else {
1969			Err(ParsingFailReasons::NotMine)
1970		}
1971	}
1972
1973	fn next_str(&mut self, expected: &'a str) -> Result<&'a str, ParsingFailReasons> {
1974		self.next_is(|v| v == expected)
1975	}
1976
1977	fn next_identifier(&mut self) -> Result<&'a str, ParsingFailReasons> {
1978		self.next_is(is_identifier)
1979	}
1980}
1981
1982#[derive(Clone)]
1983pub struct ProgramState {
1984	// pub(super) types: HashMap<String, NodeReference>,
1985}
1986
1987#[cfg(test)]
1988mod tests {
1989	use super::*;
1990	use crate::tokenizer::tokenize;
1991
1992	#[test]
1993	#[should_panic(expected = "Invalid binding array count")]
1994	fn binding_array_rejects_zero_elements() {
1995		Node::binding_array("textures", Node::combined_image_sampler(), 0, true, false, 0);
1996	}
1997
1998	#[test]
1999	fn parse_stage_interface_and_task_storage_declarations() {
2000		let tokens = tokenize(
2001			r#"
2002				instance_index: input<u32, 0>;
2003				primitive_index: output<u32, 1>;
2004				meshlet_indices: output<u32, 2, 126>;
2005				visible_meshlets: task_payload<u32, 32>;
2006				visible_count: workgroup<atomicu32>;
2007			"#,
2008		)
2009		.expect("stage-interface source should tokenize");
2010		let root = parse(&tokens).expect("stage-interface source should parse");
2011
2012		assert!(matches!(
2013			root["instance_index"].node(),
2014			Nodes::Input {
2015				format: "u32",
2016				location: 0,
2017				..
2018			}
2019		));
2020		assert!(matches!(
2021			root["primitive_index"].node(),
2022			Nodes::Output {
2023				format: "u32",
2024				location: 1,
2025				count: None,
2026				..
2027			}
2028		));
2029		assert!(matches!(
2030			root["meshlet_indices"].node(),
2031			Nodes::Output {
2032				format: "u32",
2033				location: 2,
2034				count: Some(count),
2035				..
2036			} if count.get() == 126
2037		));
2038		assert!(matches!(
2039			root["visible_meshlets"].node(),
2040			Nodes::TaskPayload {
2041				format: "u32",
2042				count,
2043				..
2044			} if count.get() == 32
2045		));
2046		assert!(matches!(
2047			root["visible_count"].node(),
2048			Nodes::Workgroup { format: "atomicu32", .. }
2049		));
2050	}
2051
2052	#[test]
2053	fn stage_interface_declarations_reject_invalid_locations_and_counts() {
2054		for source in [
2055			"value: input<u32, 256>;",
2056			"value: output<u32, 0, 0>;",
2057			"value: task_payload<u32, 0>;",
2058			"value: workgroup<u32>",
2059		] {
2060			let tokens = tokenize(source).expect("invalid declaration should still tokenize");
2061			assert!(parse(&tokens).is_err(), "expected `{source}` to be rejected");
2062		}
2063	}
2064
2065	#[test]
2066	fn parse_resource_descriptors_with_flat_slots_access_and_count() {
2067		let tokens = tokenize(
2068			r#"
2069				source: descriptor<Texture2D, 3, read>;
2070				result: descriptor<StorageImage<rgba16f>, 7, write, 4>;
2071				unformatted_result: descriptor<StorageImage, 8, write>;
2072				data: descriptor<Data, 11, read_write>;
2073				textures: descriptor<Texture2DArray, 20, read, 16>;
2074			"#,
2075		)
2076		.expect("descriptor source should tokenize");
2077		let root = parse(&tokens).expect("descriptor source should parse");
2078
2079		let Nodes::Descriptor {
2080			resource_type,
2081			slot,
2082			read,
2083			write,
2084			count,
2085			..
2086		} = root["source"].node()
2087		else {
2088			panic!("expected source descriptor");
2089		};
2090		assert_eq!(*resource_type, "Texture2D");
2091		assert_eq!(*slot, 3);
2092		assert!(*read);
2093		assert!(!*write);
2094		assert_eq!(*count, None);
2095
2096		assert!(matches!(
2097			root["result"].node(),
2098			Nodes::Descriptor {
2099				format: Some("rgba16f"),
2100				slot: 7,
2101				read: false,
2102				write: true,
2103				count: Some(count),
2104				..
2105			} if count.get() == 4
2106		));
2107		assert!(matches!(
2108			root["unformatted_result"].node(),
2109			Nodes::Descriptor {
2110				format: None,
2111				slot: 8,
2112				..
2113			}
2114		));
2115		assert!(matches!(
2116			root["data"].node(),
2117			Nodes::Descriptor {
2118				resource_type: "Data",
2119				slot: 11,
2120				read: true,
2121				write: true,
2122				..
2123			}
2124		));
2125		assert!(matches!(
2126			root["textures"].node(),
2127			Nodes::Descriptor { resource_type: "Texture2DArray", slot: 20, count: Some(count), .. }
2128				if count.get() == 16
2129		));
2130	}
2131
2132	#[test]
2133	fn parse_source_push_constant_block() {
2134		let tokens = tokenize(
2135			r#"
2136				push_constant: push_constant {
2137					source_vertex_base: u32,
2138					destination_vertex_base: u32,
2139					vertex_count: u32,
2140				}
2141			"#,
2142		)
2143		.expect("push-constant source should tokenize");
2144		let root = parse(&tokens).expect("push-constant source should parse");
2145		let Nodes::Scope { children, .. } = root.node() else {
2146			panic!("expected root scope");
2147		};
2148		assert!(matches!(
2149			children.as_slice(),
2150			[Node {
2151				node: Nodes::PushConstant { members },
2152				..
2153			}] if members.len() == 3
2154		));
2155	}
2156
2157	#[test]
2158	fn descriptor_rejects_invalid_access_count_and_arguments() {
2159		for source in [
2160			"texture: descriptor<Texture2D, 0, execute>;",
2161			"textures: descriptor<Texture2D, 0, read, 0>;",
2162			"texture: descriptor<Texture2D>;",
2163		] {
2164			let tokens = tokenize(source).expect("descriptor source should tokenize");
2165			assert!(parse(&tokens).is_err(), "malformed descriptor should be rejected: {source}");
2166		}
2167	}
2168
2169	#[test]
2170	fn descriptor_rejects_formats_on_non_storage_image_resources() {
2171		for source in [
2172			"texture: descriptor<Texture2D<rgba16f>, 0, read>;",
2173			"data: descriptor<Data<rgba16f>, 0, read>;",
2174		] {
2175			let tokens = tokenize(source).expect("formatted descriptor source should tokenize");
2176			assert!(
2177				parse(&tokens).is_err(),
2178				"non-storage image descriptor format should be rejected: {source}"
2179			);
2180		}
2181	}
2182
2183	fn assert_named_type(type_name: &TypeName<'_>, expected: &str) {
2184		assert!(matches!(type_name, TypeName::Named(name) if *name == expected));
2185	}
2186
2187	fn print_tree(node: &Node) {
2188		match &node.node {
2189			Nodes::Scope { name, children } => {
2190				println!("{}", name,);
2191				for child in children {
2192					print_tree(child);
2193				}
2194			}
2195			Nodes::Struct { name, fields } => {
2196				println!("{}", name,);
2197				for field in fields {
2198					print_tree(field);
2199				}
2200			}
2201			_ => {}
2202		}
2203	}
2204
2205	fn assert_struct(node: &Node) {
2206		if let Nodes::Struct { name, fields } = &node.node {
2207			assert_eq!(*name, "Light");
2208			assert_eq!(fields.len(), 2);
2209
2210			let position = &fields[0];
2211
2212			if let Nodes::Member { name, r#type } = &position.node {
2213				assert_eq!(*name, "position");
2214				assert_eq!(r#type, "vec3f");
2215			} else {
2216				panic!("Not a member");
2217			}
2218
2219			let color = &fields[1];
2220
2221			if let Nodes::Member { name, r#type } = &color.node {
2222				assert_eq!(*name, "color");
2223				assert_eq!(r#type, "vec3f");
2224			} else {
2225				panic!("Not a member");
2226			}
2227		} else {
2228			panic!("Not a struct");
2229		}
2230	}
2231
2232	#[test]
2233	fn test_parse_struct() {
2234		let source = "
2235Light: struct {
2236	array: u32[3],
2237	position: vec3f,
2238	color: vec3f
2239}";
2240
2241		let tokens = tokenize(source).unwrap();
2242		let node = parse(&tokens).expect("Failed to parse");
2243
2244		// program.types.get("Light").expect("Failed to get Light type");
2245
2246		if let Nodes::Struct { name, .. } = node.node {
2247			assert_eq!(name, "root");
2248			assert_struct(&node["Light"]);
2249		}
2250	}
2251
2252	fn assert_function(node: &Node) {
2253		if let Nodes::Function {
2254			name,
2255			params,
2256			return_type,
2257			statements,
2258			..
2259		} = &node.node
2260		{
2261			assert_eq!(*name, "main");
2262			assert_eq!(params.len(), 0);
2263			assert_eq!(*return_type, "void");
2264			assert_eq!(statements.len(), 2);
2265
2266			let statement = &statements[0];
2267
2268			if let Nodes::Expression(Expressions::Operator {
2269				name,
2270				left: var_decl,
2271				right: function_call,
2272			}) = &statement.node
2273			{
2274				assert_eq!(*name, "=");
2275
2276				if let Nodes::Expression(Expressions::VariableDeclaration { name, r#type, .. }) = &var_decl.node {
2277					assert_eq!(*name, "position");
2278					assert_named_type(r#type, "vec4f");
2279				} else {
2280					panic!("Not an variable declaration");
2281				}
2282
2283				if let Nodes::Expression(Expressions::Call { name, parameters, .. }) = &function_call.node {
2284					assert_named_type(name, "vec4");
2285					assert_eq!(parameters.len(), 4);
2286
2287					let x_param = &parameters[0];
2288
2289					if let Nodes::Expression(Expressions::Literal { value }) = &x_param.node {
2290						assert_eq!(value, "0.0");
2291					} else {
2292						panic!("Not a literal");
2293					}
2294				} else {
2295					panic!("Not a function call");
2296				}
2297			} else {
2298				panic!("Not an assignment");
2299			}
2300		} else {
2301			panic!("Not a function");
2302		}
2303	}
2304
2305	#[test]
2306	fn test_parse_function() {
2307		let source = "
2308main: fn () -> void {
2309	let position: vec4f = vec4(0.0, 0.0, 0.0, 1.0);
2310	gl_Position = position;
2311}";
2312
2313		let tokens = tokenize(source).unwrap();
2314		let node = parse(&tokens).expect("Failed to parse");
2315
2316		if let Nodes::Scope { name, .. } = node.node {
2317			assert_eq!(name, "root");
2318			assert_function(&node["main"]);
2319		} else {
2320			panic!("Not root node")
2321		}
2322	}
2323
2324	#[test]
2325	fn test_parse_function_with_parameters_and_return_value() {
2326		let source = "
2327		add: fn (lhs: f32, rhs: f32) -> f32 {
2328			return lhs + rhs;
2329		}";
2330
2331		let tokens = tokenize(source).unwrap();
2332		let node = parse(&tokens).expect("Failed to parse");
2333
2334		let function = &node["add"];
2335		if let Nodes::Function {
2336			name,
2337			params,
2338			return_type,
2339			statements,
2340			..
2341		} = &function.node
2342		{
2343			assert_eq!(*name, "add");
2344			assert_eq!(params.len(), 2);
2345			assert_eq!(*return_type, "f32");
2346			assert_eq!(statements.len(), 1);
2347
2348			if let Nodes::Parameter { name, r#type } = &params[0].node {
2349				assert_eq!(*name, "lhs");
2350				assert_eq!(*r#type, "f32");
2351			} else {
2352				panic!("Expected parameter");
2353			}
2354
2355			if let Nodes::Expression(Expressions::Return { value }) = &statements[0].node {
2356				let value = value.as_ref().expect("Expected return value");
2357				if let Nodes::Expression(Expressions::Operator { name, .. }) = &value.node {
2358					assert_eq!(*name, "+");
2359				} else {
2360					panic!("Expected return operator");
2361				}
2362			} else {
2363				panic!("Expected return statement");
2364			}
2365		} else {
2366			panic!("Expected function");
2367		}
2368	}
2369
2370	#[test]
2371	fn parse_operators() {
2372		let source = "
2373main: fn () -> void {
2374	let position: vec4f = vec4(0.0, 0.0, 0.0, 1.0) * 2.0;
2375	gl_Position = position;
2376}";
2377
2378		let tokens = tokenize(source).unwrap();
2379		let node = parse(&tokens).expect("Failed to parse");
2380
2381		let main_node = &node["main"];
2382
2383		if let Nodes::Function {
2384			name,
2385			statements,
2386			return_type,
2387			params,
2388			..
2389		} = &main_node.node
2390		{
2391			assert_eq!(*name, "main");
2392			assert_eq!(statements.len(), 2);
2393			assert_eq!(*return_type, "void");
2394			assert_eq!(params.len(), 0);
2395
2396			assert_eq!(statements.len(), 2);
2397
2398			let statement0 = &statements[0];
2399
2400			if let Nodes::Expression(Expressions::Operator {
2401				name,
2402				left: var_decl,
2403				right: multiply,
2404			}) = &statement0.node
2405			{
2406				assert_eq!(*name, "=");
2407
2408				if let Nodes::Expression(Expressions::VariableDeclaration { .. }) = var_decl.node {
2409				} else {
2410					panic!("Not a variable declaration");
2411				}
2412
2413				if let Nodes::Expression(Expressions::Operator {
2414					name,
2415					left: vec4,
2416					right: literal,
2417				}) = &multiply.node
2418				{
2419					assert_eq!(*name, "*");
2420
2421					if let Nodes::Expression(Expressions::Call { name, .. }) = &vec4.node {
2422						assert_named_type(name, "vec4");
2423					} else {
2424						panic!("Not a function call");
2425					}
2426
2427					if let Nodes::Expression(Expressions::Literal { value }) = &literal.node {
2428						assert_eq!(value, "2.0");
2429					} else {
2430						panic!("Not a literal");
2431					}
2432				} else {
2433					panic!("Not an operator");
2434				}
2435			} else {
2436				panic!("Not an expression");
2437			}
2438		} else {
2439			panic!("Not a feature");
2440		}
2441	}
2442
2443	#[test]
2444	fn builder_creates_assignment_expression() {
2445		let node = Node::assignment(Node::member_expression("albedo"), Node::literal_expression("1.0"));
2446
2447		let Nodes::Expression(Expressions::Operator { name, left, right }) = node.node else {
2448			panic!("Expected assignment operator");
2449		};
2450
2451		assert_eq!(name, "=");
2452		assert!(matches!(left.node, Nodes::Expression(Expressions::Member { name }) if name == "albedo"));
2453		assert!(matches!(right.node, Nodes::Expression(Expressions::Literal { value }) if value == "1.0"));
2454	}
2455
2456	#[test]
2457	fn builder_creates_call_expression() {
2458		let node = Node::call(
2459			"vec4f",
2460			vec![
2461				Node::literal_expression("1.0"),
2462				Node::literal_expression("0.0"),
2463				Node::literal_expression("0.0"),
2464				Node::literal_expression("1.0"),
2465			],
2466		);
2467
2468		let Nodes::Expression(Expressions::Call { name, parameters, .. }) = node.node else {
2469			panic!("Expected call expression");
2470		};
2471
2472		assert_named_type(&name, "vec4f");
2473		assert_eq!(parameters.len(), 4);
2474	}
2475
2476	#[test]
2477	fn builder_creates_variable_declaration_assignment() {
2478		let node = Node::let_assignment("roughness", "f32", Node::literal_expression("0.5"));
2479
2480		let Nodes::Expression(Expressions::Operator { name, left, right }) = node.node else {
2481			panic!("Expected assignment operator");
2482		};
2483
2484		assert_eq!(name, "=");
2485		assert!(matches!(
2486			left.node,
2487			Nodes::Expression(Expressions::VariableDeclaration { name, r#type, .. })
2488				if name == "roughness" && matches!(r#type, TypeName::Named("f32")),
2489		));
2490		assert!(matches!(right.node, Nodes::Expression(Expressions::Literal { value }) if value == "0.5"));
2491	}
2492
2493	#[test]
2494	fn builder_program_lexes() {
2495		let program = Node::root_with_children(vec![Node::main_function(vec![Node::let_assignment(
2496			"albedo",
2497			"vec4f",
2498			Node::call(
2499				"vec4f",
2500				vec![
2501					Node::literal_expression("1.0"),
2502					Node::literal_expression("0.0"),
2503					Node::literal_expression("0.0"),
2504					Node::literal_expression("1.0"),
2505				],
2506			),
2507		)])]);
2508
2509		crate::lex(program).expect("builder generated program should lex");
2510	}
2511
2512	#[test]
2513	fn parse_accessor() {
2514		let source = "
2515main: fn () -> void {
2516	let position: vec4f = vec4(0.0, 0.0, 0.0, 1.0) * 2.0;
2517	position.y = 2.0;
2518	gl_Position = position;
2519}";
2520
2521		let tokens = tokenize(source).unwrap();
2522		let node = parse(&tokens).expect("Failed to parse");
2523
2524		print_tree(&node);
2525
2526		if let Nodes::Scope { children, .. } = &node.node {
2527			assert_eq!(children.len(), 1);
2528
2529			let main_node = &node["main"];
2530
2531			if let Nodes::Function { name, statements, .. } = &main_node.node {
2532				assert_eq!(*name, "main");
2533				assert_eq!(statements.len(), 3);
2534
2535				let statement1 = &statements[1];
2536
2537				if let Nodes::Expression(Expressions::Operator {
2538					name,
2539					left: accessor,
2540					right: literal,
2541				}) = &statement1.node
2542				{
2543					assert_eq!(*name, "=");
2544
2545					if let Nodes::Expression(Expressions::Accessor {
2546						left: position,
2547						right: y,
2548					}) = &accessor.node
2549					{
2550						if let Nodes::Expression(Expressions::Member { name }) = &position.node {
2551							assert_eq!(name, "position");
2552						} else {
2553							panic!("Not a member");
2554						}
2555
2556						if let Nodes::Expression(Expressions::Member { name }) = &y.node {
2557							assert_eq!(name, "y");
2558						} else {
2559							panic!("Not a member");
2560						}
2561					} else {
2562						panic!("Not an accessor");
2563					}
2564
2565					if let Nodes::Expression(Expressions::Literal { value }) = &literal.node {
2566						assert_eq!(value, "2.0");
2567					} else {
2568						panic!("Not a literal");
2569					}
2570				} else {
2571					panic!("Not an operator");
2572				}
2573			} else {
2574				panic!("Not a function");
2575			}
2576		} else {
2577			panic!("Not root node")
2578		}
2579	}
2580
2581	#[test]
2582	fn test_parse_struct_and_function() {
2583		let source = "
2584Light: struct {
2585	position: vec3f,
2586	color: vec3f
2587}
2588
2589#[vertex]
2590main: fn () -> void {
2591	let position: vec4f = vec4(0.0, 0.0, 0.0, 1.0);
2592	gl_Position = position;
2593}";
2594
2595		let tokens = tokenize(source).expect("Failed to tokenize");
2596		let node = parse(&tokens).expect("Failed to parse");
2597
2598		if let Nodes::Scope { .. } = &node.node {
2599			assert_struct(&node["Light"]);
2600			assert_function(&node["main"]);
2601		} else {
2602			panic!("Not root node")
2603		}
2604	}
2605
2606	#[test]
2607	fn test_parse_member() {
2608		let source = "color: In<vec4f>;";
2609
2610		let tokens = tokenize(source).expect("Failed to tokenize");
2611		let node = parse(&tokens).expect("Failed to parse");
2612
2613		if let Nodes::Scope { .. } = &node.node {
2614			let member_node = &node["color"];
2615
2616			if let Nodes::Member { name, r#type } = &member_node.node {
2617				assert_eq!(*name, "color");
2618				assert_eq!(r#type, "In<vec4f>");
2619			} else {
2620				panic!("Not a feature");
2621			}
2622		}
2623	}
2624
2625	#[test]
2626	fn test_parse_multiple_functions() {
2627		let source = "
2628used: fn () -> void {}
2629not_used: fn () -> void {}
2630
2631main: fn () -> void {
2632	used();
2633}";
2634
2635		let tokens = tokenize(source).expect("Failed to tokenize");
2636		let node = parse(&tokens).expect("Failed to parse");
2637
2638		if let Nodes::Scope { children, .. } = node.node {
2639			assert_eq!(children.len(), 3);
2640		}
2641	}
2642
2643	#[test]
2644	fn fragment_shader() {
2645		let source = r#"
2646		main: fn () -> void {
2647			let albedo: vec3f = vec3f(1.0, 0.0, 0.0);
2648		}
2649		"#;
2650
2651		let tokens = tokenize(source).expect("Failed to tokenize");
2652		let node = parse(&tokens).expect("Failed to parse");
2653
2654		if let Nodes::Scope { children, .. } = node.node {
2655			assert_eq!(children.len(), 1);
2656		}
2657	}
2658
2659	#[test]
2660	fn test_parse_accessor_and_assignment() {
2661		let source = "
2662main: fn () -> void {
2663	let n: f32 = intrinsic(0).y;
2664}";
2665
2666		let tokens = tokenize(source).expect("Failed to tokenize");
2667		let node = parse(&tokens).expect("Failed to parse");
2668
2669		if let Nodes::Scope { children, .. } = &node.node {
2670			assert_eq!(children.len(), 1);
2671
2672			let main_node = &node["main"];
2673
2674			if let Nodes::Function { name, statements, .. } = &main_node.node {
2675				assert_eq!(*name, "main");
2676				assert_eq!(statements.len(), 1);
2677
2678				let statement = &statements[0];
2679
2680				if let Nodes::Expression(Expressions::Operator { name, left, right }) = &statement.node {
2681					assert_eq!(*name, "=");
2682
2683					if let Nodes::Expression(Expressions::VariableDeclaration { name, r#type, .. }) = &left.node {
2684						assert_eq!(*name, "n");
2685						assert_named_type(r#type, "f32");
2686					} else {
2687						panic!("Not a variable declaration");
2688					}
2689
2690					if let Nodes::Expression(Expressions::Accessor { left, right }) = &right.node {
2691						if let Nodes::Expression(Expressions::Call { name, parameters, .. }) = &left.node {
2692							assert_named_type(name, "intrinsic");
2693							assert_eq!(parameters.len(), 1);
2694
2695							if let Nodes::Expression(Expressions::Literal { value }) = &parameters[0].node {
2696								assert_eq!(value, "0");
2697							} else {
2698								panic!("Not a literal");
2699							}
2700						} else {
2701							panic!("Not a function call");
2702						}
2703
2704						if let Nodes::Expression(Expressions::Member { name }) = &right.node {
2705							assert_eq!(name, "y");
2706						} else {
2707							panic!("Not a member");
2708						}
2709					} else {
2710						panic!("Not an accessor");
2711					}
2712				} else {
2713					panic!("Not an operator");
2714				}
2715			} else {
2716				panic!("Not a function");
2717			}
2718		} else {
2719			panic!("Not root node")
2720		}
2721	}
2722
2723	#[test]
2724	fn parse_array_index_accessor() {
2725		let source = "
2726main: fn () -> void {
2727	let n: u32 = values[1];
2728}";
2729
2730		let tokens = tokenize(source).expect("Failed to tokenize");
2731		let node = parse(&tokens).expect("Failed to parse");
2732
2733		let main_node = &node["main"];
2734		if let Nodes::Function { statements, .. } = &main_node.node {
2735			let statement = &statements[0];
2736			if let Nodes::Expression(Expressions::Operator { right, .. }) = &statement.node {
2737				if let Nodes::Expression(Expressions::Accessor { left, right }) = &right.node {
2738					assert!(matches!(&left.node, Nodes::Expression(Expressions::Member { name }) if name == "values"));
2739					assert!(matches!(
2740						right.node,
2741						Nodes::Expression(Expressions::Expression(ref elements))
2742							if elements.len() == 1
2743								&& matches!(&elements[0].node, Nodes::Expression(Expressions::Literal { value }) if value == "1")
2744					));
2745				} else {
2746					panic!("Not an accessor");
2747				}
2748			} else {
2749				panic!("Not an operator");
2750			}
2751		} else {
2752			panic!("Not a function");
2753		}
2754	}
2755
2756	#[test]
2757	fn parse_comparison_and_continue() {
2758		let source = r#"
2759		main: fn () -> void {
2760			for (let i: u32 = 0; i <= 4; i = i + 1) {
2761				if (i >= 2) {
2762					continue;
2763				}
2764			}
2765		}
2766		"#;
2767
2768		let tokens = tokenize(source).expect("Failed to tokenize");
2769		let node = parse(&tokens).expect("Failed to parse");
2770		let main_node = &node["main"];
2771
2772		let Nodes::Function { statements, .. } = &main_node.node else {
2773			panic!("Expected function");
2774		};
2775
2776		let Nodes::ForLoop {
2777			condition, statements, ..
2778		} = &statements[0].node
2779		else {
2780			panic!("Expected for loop");
2781		};
2782
2783		assert!(matches!(
2784			&condition.node,
2785			Nodes::Expression(Expressions::Operator { name, .. }) if *name == "<="
2786		));
2787
2788		let Nodes::Conditional { condition, statements } = &statements[0].node else {
2789			panic!("Expected conditional");
2790		};
2791
2792		assert!(matches!(
2793			&condition.node,
2794			Nodes::Expression(Expressions::Operator { name, .. }) if *name == ">="
2795		));
2796		assert!(matches!(statements[0].node, Nodes::Expression(Expressions::Continue)));
2797	}
2798
2799	#[test]
2800	fn test_parse_const() {
2801		let source = "
2802PI: const f32 = 3.14;
2803";
2804
2805		let tokens = tokenize(source).expect("Failed to tokenize");
2806		let node = parse(&tokens).expect("Failed to parse");
2807
2808		if let Nodes::Scope { children, .. } = &node.node {
2809			assert_eq!(children.len(), 1);
2810
2811			let const_node = &node["PI"];
2812
2813			if let Nodes::Const { name, r#type, value, .. } = &const_node.node {
2814				assert_eq!(*name, "PI");
2815				assert_named_type(r#type, "f32");
2816
2817				if let Nodes::Expression(Expressions::Literal { value }) = &value.node {
2818					assert_eq!(*value, "3.14");
2819				} else {
2820					panic!("Expected a literal value, got: {:?}", value.node);
2821				}
2822			} else {
2823				panic!("Expected a const node, got: {:?}", const_node.node);
2824			}
2825		} else {
2826			panic!("Not root node");
2827		}
2828	}
2829
2830	#[test]
2831	fn test_parse_const_with_expression() {
2832		let source = "
2833TAU: const f32 = 3.14 * 2.0;
2834";
2835
2836		let tokens = tokenize(source).expect("Failed to tokenize");
2837		let node = parse(&tokens).expect("Failed to parse");
2838
2839		let const_node = &node["TAU"];
2840
2841		if let Nodes::Const { name, r#type, value, .. } = &const_node.node {
2842			assert_eq!(*name, "TAU");
2843			assert_named_type(r#type, "f32");
2844
2845			if let Nodes::Expression(Expressions::Operator { name, .. }) = &value.node {
2846				assert_eq!(*name, "*");
2847			} else {
2848				panic!("Expected an operator expression, got: {:?}", value.node);
2849			}
2850		} else {
2851			panic!("Expected a const node");
2852		}
2853	}
2854
2855	#[test]
2856	fn test_parse_const_array() {
2857		let source = "
2858		WEIGHTS: const f32 [ 3 ] = f32 [ 3 ](0.5, 0.25, 0.125);
2859";
2860
2861		let tokens = tokenize(source).expect("Failed to tokenize");
2862		let node = parse(&tokens).expect("Failed to parse");
2863
2864		let const_node = &node["WEIGHTS"];
2865
2866		if let Nodes::Const { name, r#type, value } = &const_node.node {
2867			assert_eq!(*name, "WEIGHTS");
2868			assert_eq!(
2869				r#type,
2870				&TypeName::Array {
2871					element: Box::new(TypeName::Named("f32")),
2872					count: 3,
2873				}
2874			);
2875
2876			if let Nodes::Expression(Expressions::Call { name, parameters }) = &value.node {
2877				assert_eq!(
2878					name,
2879					&TypeName::Array {
2880						element: Box::new(TypeName::Named("f32")),
2881						count: 3,
2882					}
2883				);
2884				assert_eq!(parameters.len(), 3);
2885			} else {
2886				panic!("Expected an array constructor call, got: {:?}", value.node);
2887			}
2888		} else {
2889			panic!("Expected a const node");
2890		}
2891	}
2892
2893	#[test]
2894	fn parse_nested_array_type_without_flattening() {
2895		let tokens = tokenize("f32 [ 3 ] [ 4 ]").expect("Failed to tokenize");
2896		let mut tokens = tokens.tokens.iter();
2897		let base_type = tokens.next().expect("Expected a base type");
2898		let (type_name, mut iterator) = parse_type_name(tokens, base_type).expect("Failed to parse type");
2899
2900		assert_eq!(
2901			type_name,
2902			TypeName::Array {
2903				element: Box::new(TypeName::Array {
2904					element: Box::new(TypeName::Named("f32")),
2905					count: 3,
2906				}),
2907				count: 4,
2908			}
2909		);
2910		assert!(iterator.next().is_none());
2911	}
2912
2913	#[test]
2914	fn parse_conditional_block() {
2915		let source = "
2916main: fn () -> void {
2917	let n: u32 = 0;
2918	if (n < 1) {
2919		n = 2;
2920	}
2921}";
2922
2923		let tokens = tokenize(source).expect("Failed to tokenize");
2924		let node = parse(&tokens).expect("Failed to parse");
2925
2926		let main_node = &node["main"];
2927		if let Nodes::Function { statements, .. } = &main_node.node {
2928			assert_eq!(statements.len(), 2);
2929
2930			let conditional = &statements[1];
2931			if let Nodes::Conditional { condition, statements } = &conditional.node {
2932				assert_eq!(statements.len(), 1);
2933
2934				assert!(matches!(
2935					condition.node,
2936					Nodes::Expression(Expressions::Operator { name, .. }) if name == "<"
2937				));
2938
2939				assert!(matches!(
2940					statements[0].node,
2941					Nodes::Expression(Expressions::Operator { name, .. }) if name == "="
2942				));
2943			} else {
2944				panic!("Expected conditional block");
2945			}
2946		} else {
2947			panic!("Expected main function");
2948		}
2949	}
2950
2951	#[test]
2952	fn parse_for_loop_block() {
2953		let source = "
2954main: fn () -> void {
2955	let sum: u32 = 0;
2956	for (let i: u32 = 0; i < 4; i = i + 1) {
2957		sum = sum + i;
2958	}
2959}";
2960
2961		let tokens = tokenize(source).expect("Failed to tokenize");
2962		let node = parse(&tokens).expect("Failed to parse");
2963
2964		let main_node = &node["main"];
2965		let Nodes::Function { statements, .. } = &main_node.node else {
2966			panic!("Expected main function");
2967		};
2968
2969		assert_eq!(statements.len(), 2);
2970
2971		let for_loop = &statements[1];
2972		let Nodes::ForLoop {
2973			initializer,
2974			condition,
2975			update,
2976			statements,
2977		} = &for_loop.node
2978		else {
2979			panic!("Expected for loop block");
2980		};
2981
2982		assert!(matches!(
2983			initializer.node,
2984			Nodes::Expression(Expressions::Operator { name, .. }) if name == "="
2985		));
2986		assert!(matches!(
2987			condition.node,
2988			Nodes::Expression(Expressions::Operator { name, .. }) if name == "<"
2989		));
2990		assert!(matches!(
2991			update.node,
2992			Nodes::Expression(Expressions::Operator { name, .. }) if name == "="
2993		));
2994		assert_eq!(statements.len(), 1);
2995	}
2996
2997	#[test]
2998	fn parse_bitwise_expression() {
2999		let source = "
3000main: fn () -> void {
3001	let packed: u32 = 1 << 8 | 2 & 255;
3002}";
3003
3004		let tokens = tokenize(source).expect("Failed to tokenize");
3005		let node = parse(&tokens).expect("Failed to parse");
3006
3007		let main_node = &node["main"];
3008		let Nodes::Function { statements, .. } = &main_node.node else {
3009			panic!("Expected main function");
3010		};
3011
3012		let Nodes::Expression(Expressions::Operator { name, right, .. }) = &statements[0].node else {
3013			panic!("Expected assignment expression");
3014		};
3015		assert_eq!(*name, "=");
3016
3017		let Nodes::Expression(Expressions::Operator { name, left, right }) = &right.node else {
3018			panic!("Expected bitwise or expression");
3019		};
3020		assert_eq!(*name, "|");
3021
3022		assert!(matches!(
3023			left.node,
3024			Nodes::Expression(Expressions::Operator { name, .. }) if name == "<<"
3025		));
3026		assert!(matches!(
3027			right.node,
3028			Nodes::Expression(Expressions::Operator { name, .. }) if name == "&"
3029		));
3030	}
3031
3032	#[test]
3033	fn parse_compute_vertex_position() {
3034		let source = r#"
3035compute_vertex_position: fn (mesh: Mesh, meshlet: Meshlet, primitive_index: u32) -> vec4f {
3036	let vertex_index: u32 = compute_vertex_index(mesh, meshlet, primitive_index);
3037	return vec4f(
3038		vertex_positions.positions[vertex_index].x,
3039		vertex_positions.positions[vertex_index].y,
3040		vertex_positions.positions[vertex_index].z,
3041		1.0
3042	);
3043}
3044"#;
3045		let tokens = tokenize(source).expect("Failed to tokenize");
3046		let node = parse(&tokens).expect("Failed to parse");
3047		let func = &node["compute_vertex_position"];
3048		assert!(matches!(&func.node, Nodes::Function { .. }));
3049	}
3050
3051	#[test]
3052	fn parse_compute_triangle() {
3053		let source = r#"
3054compute_triangle: fn (mesh: Mesh, meshlet: Meshlet, primitive_index: u32) -> vec3u {
3055	return vec3u(
3056		primitive_indices.primitive_indices[(mesh.base_triangle_index + u16_to_u32(meshlet.triangle_offset) + primitive_index) * 3 + 0],
3057		primitive_indices.primitive_indices[(mesh.base_triangle_index + u16_to_u32(meshlet.triangle_offset) + primitive_index) * 3 + 1],
3058		primitive_indices.primitive_indices[(mesh.base_triangle_index + u16_to_u32(meshlet.triangle_offset) + primitive_index) * 3 + 2]
3059	);
3060}
3061"#;
3062		let tokens = tokenize(source).expect("Failed to tokenize");
3063		println!("Tokens: {:?}", tokens.tokens);
3064		let node = parse(&tokens).expect("Failed to parse");
3065		let func = &node["compute_triangle"];
3066		assert!(matches!(&func.node, Nodes::Function { .. }));
3067	}
3068
3069	#[test]
3070	fn parse_grouping_parentheses() {
3071		// Minimal repro: grouping parentheses inside a function call
3072		let source = r#"
3073main: fn () -> void {
3074	foo((a + b) * 3);
3075}
3076"#;
3077		let tokens = tokenize(source).expect("Failed to tokenize");
3078		println!("Tokens: {:?}", tokens.tokens);
3079		let node = parse(&tokens).expect("Failed to parse");
3080		let func = &node["main"];
3081		assert!(matches!(&func.node, Nodes::Function { .. }));
3082	}
3083
3084	#[test]
3085	fn parse_conditional_comparing_a_push_constant_member() {
3086		let source = r#"
3087main: fn () -> void {
3088	let local_vertex_index: u32 = thread_id().x;
3089	if (local_vertex_index >= push_constant.vertex_count) {
3090		return;
3091	}
3092}
3093"#;
3094		let tokens = tokenize(source).expect("Failed to tokenize");
3095		let node = parse(&tokens).expect("Failed to parse push-constant comparison");
3096		let func = &node["main"];
3097		assert!(matches!(&func.node, Nodes::Function { .. }));
3098	}
3099
3100	#[test]
3101	fn parse_grouped_arithmetic_inside_a_conditional() {
3102		let source = r#"
3103main: fn () -> void {
3104	if (total_weight > 0.00000001) {
3105		let column0: vec4f = (
3106			matrix0.column0 * weights.x
3107			+ matrix1.column0 * weights.y
3108		) * inverse_total_weight;
3109	}
3110}
3111"#;
3112		let tokens = tokenize(source).expect("Failed to tokenize");
3113		let node = parse(&tokens).expect("Failed to parse grouped conditional arithmetic");
3114		let func = &node["main"];
3115		assert!(matches!(&func.node, Nodes::Function { .. }));
3116	}
3117
3118	#[test]
3119	fn parse_process_meshlet() {
3120		let source = r#"
3121process_meshlet: fn (instance_index: u32, matrix: mat4f) -> void {
3122	let mesh: Mesh = meshes.meshes[instance_index];
3123	let meshlet_index: u32 = threadgroup_position() + mesh.base_meshlet_index;
3124	let meshlet: Meshlet = meshlets.meshlets[meshlet_index];
3125	let primitive_index: u32 = thread_idx();
3126
3127	set_mesh_output_counts(u8_to_u32(meshlet.primitive_count), u8_to_u32(meshlet.triangle_count));
3128
3129	if (primitive_index < u8_to_u32(meshlet.primitive_count)) {
3130		set_mesh_vertex_position(
3131			primitive_index,
3132			matrix * mesh.model * compute_vertex_position(mesh, meshlet, primitive_index)
3133		);
3134	}
3135
3136	if (primitive_index < u8_to_u32(meshlet.triangle_count)) {
3137		set_mesh_triangle(primitive_index, compute_triangle(mesh, meshlet, primitive_index));
3138		out_instance_index[primitive_index] = instance_index;
3139		out_primitive_index[primitive_index] = meshlet_index << 8 | primitive_index & 255;
3140	}
3141}
3142"#;
3143		let tokens = tokenize(source).expect("Failed to tokenize");
3144		let node = parse(&tokens).expect("Failed to parse");
3145		let func = &node["process_meshlet"];
3146		assert!(matches!(&func.node, Nodes::Function { .. }));
3147	}
3148
3149	#[test]
3150	fn truncated_function_returns_an_error() {
3151		let tokens = tokenize("main: fn () -> void {").expect("Failed to tokenize");
3152
3153		assert!(matches!(parse(&tokens), Err(ParsingFailReasons::BadSyntax { .. })));
3154	}
3155}