1use crate::tokenizer;
20
21pub type NodeReference<'a> = &'a Node<'a>;
23
24#[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
40pub(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 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 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 &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 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 if let Nodes::Scope { children, .. } = &mut self.node {
467 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()); }
480 }
481}
482
483#[derive(Clone, Debug)]
484pub enum Nodes<'a> {
485 Null,
487 Scope {
489 name: &'a str,
491 children: Vec<Node<'a>>,
492 },
493 Struct {
495 name: &'a str,
496 fields: Vec<Node<'a>>,
497 },
498 Member {
500 name: &'a str,
501 r#type: String,
502 },
503 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 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 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 Specialization {
541 name: &'a str,
542 r#type: &'a str,
543 },
544 PushConstant {
546 members: Vec<Node<'a>>,
547 },
548 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 TaskPayload {
585 name: &'a str,
586 format: &'a str,
587 count: NonZeroUsize,
588 },
589 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 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 NotMine,
682 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
773type FeatureParserResult<'i, 'a> = Result<(Node<'a>, std::slice::Iter<'i, &'a str>), ParsingFailReasons>;
775
776type 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
782fn 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 }) }
812
813fn 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
827fn 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 }) }
858
859fn 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 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 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
961fn 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
1107fn 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
1220fn 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 })?; 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 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
1403fn 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
1518fn 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 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 expressions.push(Atoms::GroupedExpression(inner_expressions));
1534
1535 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 if **iterator
1756 .clone()
1757 .peekable()
1758 .peek()
1759 .ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1760 == ","
1761 {
1762 iterator.next();
1763 }
1764
1765 if **iterator
1767 .clone()
1768 .peekable()
1769 .peek()
1770 .ok_or(ParsingFailReasons::StreamEndedPrematurely)?
1771 == ")"
1772 {
1773 iterator.next();
1774 break;
1775 }
1776
1777 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(";")?; 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 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 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 }
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 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 = ¶meters[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 } = ¶ms[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 }) = ¶meters[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 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}