wgsl_parser/
expr.rs

1//! A module for the syntax nodes representing WGSL expressions.
2
3use std::{fmt, sync::Arc};
4
5use gramatika::{debug, Parse, ParseStreamer, Result, Span, Spanned, SpannedError, Token as _};
6
7use crate::{
8	common::{ArgumentList, TypeDecl},
9	token::{brace, keyword, operator, punct},
10	ParseStream, Token, TokenKind,
11};
12
13#[derive(Clone, DebugLisp)]
14pub enum Expr {
15	UnaryPre(UnaryPreExpr),
16	UnaryPost(UnaryPostExpr),
17	Binary(BinaryExpr),
18	Assignment(BinaryExpr),
19	FnCall(FnCallExpr),
20	TypeCtor(TypeCtorExpr),
21	Group(GroupExpr),
22	Bitcast(BitcastExpr),
23	Literal(Token),
24	Ident(IdentExpr),
25	Primary(PrimaryExpr),
26}
27
28#[derive(Clone, DebugLisp)]
29pub struct UnaryPreExpr {
30	pub op: Token,
31	pub expr: Arc<Expr>,
32}
33
34#[derive(Clone, DebugLisp)]
35pub struct UnaryPostExpr {
36	pub expr: Arc<Expr>,
37	pub op: Token,
38}
39
40#[derive(Clone, DebugLisp)]
41pub struct BinaryExpr {
42	pub lhs: Arc<Expr>,
43	pub op: Token,
44	pub rhs: Arc<Expr>,
45}
46
47#[derive(Clone, DebugLisp)]
48pub struct FnCallExpr {
49	pub ident: IdentExpr,
50	pub arguments: ArgumentList,
51}
52
53#[derive(Clone, DebugLisp)]
54pub struct TypeCtorExpr {
55	pub ty: TypeDecl,
56	pub arguments: ArgumentList,
57}
58
59#[derive(Clone, DebugLisp)]
60pub struct GroupExpr {
61	pub brace_open: Token,
62	pub expr: Arc<Expr>,
63	pub brace_close: Token,
64}
65
66#[derive(Clone, DebugLisp)]
67pub struct BitcastExpr {
68	pub keyword: Token,
69	pub ty: TypeDecl,
70	pub expr: GroupExpr,
71}
72
73#[derive(Clone, DebugLisp)]
74pub enum IdentExpr {
75	Namespaced(NamespacedIdent),
76	Leaf(Token),
77}
78
79#[derive(Clone, DebugLisp)]
80pub struct NamespacedIdent {
81	pub namespace: Token,
82	pub ident: Arc<IdentExpr>,
83}
84
85#[derive(Clone, DebugLisp)]
86pub enum IdentExprBuilder {
87	Namespaced(NamespacedIdentBuilder),
88	Leaf(Token),
89}
90
91#[derive(Clone, DebugLisp)]
92pub struct NamespacedIdentBuilder {
93	pub namespace: Token,
94	pub ident: Box<IdentExprBuilder>,
95}
96
97#[derive(Clone, DebugLisp)]
98pub struct PrimaryExpr {
99	pub expr: Arc<Expr>,
100	pub postfix: Option<PostfixExpr>,
101}
102
103struct PrimaryExprBuilder {
104	pub expr: Box<Expr>,
105	pub postfix: Option<PostfixExpr>,
106}
107
108#[derive(Clone, DebugLisp)]
109pub struct PostfixExpr {
110	pub accessor: Accessor,
111	pub expr: Arc<Expr>,
112	pub postfix: Option<Arc<PostfixExpr>>,
113}
114
115#[derive(Clone)]
116pub enum Accessor {
117	Dot(Token),
118	Index([Token; 2]),
119}
120
121impl gramatika::DebugLisp for Accessor {
122	fn fmt(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
123		match self {
124			Accessor::Dot(token) => write!(f, "(Accessor::Dot {:?})", token),
125			Accessor::Index(tokens) => {
126				writeln!(f, "(Accessor::Index")?;
127				for token in tokens {
128					write!(f, "{}", debug::INDENT.repeat(indent + 1))?;
129					writeln!(f, "{:?},", token)?;
130				}
131				write!(f, "{})", debug::INDENT.repeat(indent))
132			}
133		}
134	}
135}
136
137// -- Recursive descent trait ------------------------------------------------------------
138
139trait RecursiveDescent {
140	type Token: gramatika::Token;
141
142	fn assignment(&mut self) -> Result<Expr>;
143	fn short_circuit_or(&mut self) -> Result<Expr>;
144	fn short_circuit_and(&mut self) -> Result<Expr>;
145	fn inclusive_or(&mut self) -> Result<Expr>;
146	fn exclusive_or(&mut self) -> Result<Expr>;
147	fn and(&mut self) -> Result<Expr>;
148	fn equality(&mut self) -> Result<Expr>;
149	fn relational(&mut self) -> Result<Expr>;
150	fn shift(&mut self) -> Result<Expr>;
151	fn additive(&mut self) -> Result<Expr>;
152	fn multiplicative(&mut self) -> Result<Expr>;
153	fn unary(&mut self) -> Result<Expr>;
154	fn binary(
155		&mut self,
156		operators: &[Self::Token],
157		operand_method: fn(&mut Self) -> Result<Expr>,
158	) -> Result<Expr>;
159}
160
161// --- gramatika impls -------------------------------------------------------------------
162
163impl Spanned for Expr {
164	fn span(&self) -> Span {
165		match self {
166			Expr::UnaryPre(inner) => inner.span(),
167			Expr::UnaryPost(inner) => inner.span(),
168			Expr::Binary(inner) => inner.span(),
169			Expr::Assignment(inner) => inner.span(),
170			Expr::FnCall(inner) => inner.span(),
171			Expr::TypeCtor(inner) => inner.span(),
172			Expr::Group(inner) => inner.span(),
173			Expr::Bitcast(inner) => inner.span(),
174			Expr::Literal(inner) => inner.span(),
175			Expr::Ident(inner) => inner.span(),
176			Expr::Primary(inner) => inner.span(),
177		}
178	}
179}
180
181impl Spanned for PrimaryExpr {
182	fn span(&self) -> Span {
183		match self.postfix {
184			Some(ref postfix) => self.expr.span().through(postfix.span()),
185			None => self.expr.span(),
186		}
187	}
188}
189
190impl Spanned for PostfixExpr {
191	fn span(&self) -> Span {
192		match self.postfix {
193			Some(ref postfix) => self.expr.span().through(postfix.span()),
194			None => self.expr.span(),
195		}
196	}
197}
198
199impl Spanned for IdentExpr {
200	fn span(&self) -> Span {
201		match self {
202			IdentExpr::Leaf(name) => name.span(),
203			IdentExpr::Namespaced(NamespacedIdent { namespace, ident }) => {
204				namespace.span().through(ident.span())
205			}
206		}
207	}
208}
209
210impl Spanned for FnCallExpr {
211	fn span(&self) -> Span {
212		self.ident.span().through(self.arguments.brace_close.span())
213	}
214}
215
216impl Spanned for BinaryExpr {
217	fn span(&self) -> Span {
218		self.lhs.span().through(self.rhs.span())
219	}
220}
221
222impl Spanned for UnaryPreExpr {
223	fn span(&self) -> Span {
224		self.op.span().through(self.expr.span())
225	}
226}
227
228impl Spanned for UnaryPostExpr {
229	fn span(&self) -> Span {
230		self.expr.span().through(self.op.span())
231	}
232}
233
234impl Spanned for TypeCtorExpr {
235	fn span(&self) -> Span {
236		self.ty.span().through(self.arguments.brace_close.span())
237	}
238}
239
240impl Spanned for GroupExpr {
241	fn span(&self) -> Span {
242		self.brace_open.span().through(self.brace_close.span())
243	}
244}
245
246impl Spanned for BitcastExpr {
247	fn span(&self) -> Span {
248		self.keyword.span().through(self.expr.brace_close.span())
249	}
250}
251
252impl Parse for Expr {
253	type Stream = ParseStream;
254
255	fn parse(input: &mut Self::Stream) -> Result<Self> {
256		input.assignment()
257	}
258}
259
260impl Parse for PrimaryExprBuilder {
261	type Stream = ParseStream;
262
263	fn parse(input: &mut Self::Stream) -> Result<Self> {
264		use TokenKind::*;
265
266		let expr = match input.peek() {
267			Some(token) => match token.as_matchable() {
268				(Type, _, _) => Ok(Expr::TypeCtor(input.parse::<TypeCtorExpr>()?)),
269				(Brace, "(", _) => Ok(Expr::Group(input.parse::<GroupExpr>()?)),
270				(Keyword, "bitcast", _) => Ok(Expr::Bitcast(input.parse::<BitcastExpr>()?)),
271				(IntLiteral, _, _) | (FloatLiteral, _, _) | (Keyword, "true" | "false", _) => {
272					let token = input.next().unwrap();
273					Ok(Expr::Literal(token))
274				}
275				(Ident, _, _) => {
276					let mut ident = input.parse::<IdentExprBuilder>()?;
277
278					if input.check(brace!["("]) {
279						let mut expr = &mut ident;
280						while let IdentExprBuilder::Namespaced(NamespacedIdentBuilder {
281							ident,
282							..
283						}) = expr
284						{
285							expr = ident.as_mut();
286						}
287						let IdentExprBuilder::Leaf(name) = expr else {
288							unreachable!();
289						};
290						*name = input.upgrade_last(TokenKind::Ident, Token::function)?;
291						let arguments = input.parse::<ArgumentList>()?;
292
293						Ok(Expr::FnCall(FnCallExpr {
294							ident: ident.build(),
295							arguments,
296						}))
297					} else {
298						Ok(Expr::Ident(ident.build()))
299					}
300				}
301				(_, _, span) => Err(SpannedError {
302					message: "Expected expression".into(),
303					span: Some(span),
304					source: input.source(),
305				}),
306			},
307			None => Err(SpannedError {
308				message: "Unexpected end of input".into(),
309				source: input.source(),
310				span: input.prev().map(|token| token.span()),
311			}),
312		}?;
313
314		let postfix = match input.peek().map(|t| t.as_matchable()) {
315			Some((Punct, ".", _) | (Brace, "[", _)) => Some(input.parse::<PostfixExpr>()?),
316			_ => None,
317		};
318
319		Ok(PrimaryExprBuilder {
320			expr: Box::new(expr),
321			postfix,
322		})
323	}
324}
325
326impl PrimaryExprBuilder {
327	fn build(self) -> PrimaryExpr {
328		PrimaryExpr {
329			expr: self.expr.into(),
330			postfix: self.postfix,
331		}
332	}
333}
334
335impl Parse for FnCallExpr {
336	type Stream = ParseStream;
337
338	fn parse(input: &mut Self::Stream) -> Result<Self> {
339		let mut ident = input.parse::<IdentExprBuilder>()?;
340
341		// TODO: Is this needed? We're already upgrading in `PrimaryExprBuilder::Parse`
342		let mut expr = &mut ident;
343		while let IdentExprBuilder::Namespaced(NamespacedIdentBuilder { ident, .. }) = expr {
344			expr = ident.as_mut();
345		}
346		let IdentExprBuilder::Leaf(name) = expr else {
347			unreachable!();
348		};
349		*name = input.upgrade_last(TokenKind::Ident, Token::function)?;
350
351		let arguments = input.parse::<ArgumentList>()?;
352
353		Ok(Self {
354			ident: ident.build(),
355			arguments,
356		})
357	}
358}
359
360impl Parse for TypeCtorExpr {
361	type Stream = ParseStream;
362
363	fn parse(input: &mut Self::Stream) -> Result<Self> {
364		let ty = input.parse::<TypeDecl>()?;
365		let arguments = input.parse::<ArgumentList>()?;
366
367		Ok(Self { ty, arguments })
368	}
369}
370
371impl Parse for GroupExpr {
372	type Stream = ParseStream;
373
374	fn parse(input: &mut Self::Stream) -> Result<Self> {
375		let brace_open = input.consume(brace!["("])?;
376		let expr = input.parse::<Expr>()?;
377		let brace_close = input.consume(brace![")"])?;
378
379		Ok(Self {
380			brace_open,
381			expr: Arc::new(expr),
382			brace_close,
383		})
384	}
385}
386
387impl Parse for BitcastExpr {
388	type Stream = ParseStream;
389
390	fn parse(input: &mut Self::Stream) -> Result<Self> {
391		let keyword = input.consume(keyword![bitcast])?;
392		input.consume(operator![<])?;
393		let ty = input.parse::<TypeDecl>()?;
394		input.consume(operator![>])?;
395		let expr = input.parse::<GroupExpr>()?;
396
397		Ok(Self { keyword, ty, expr })
398	}
399}
400
401impl Parse for IdentExprBuilder {
402	type Stream = ParseStream;
403
404	fn parse(input: &mut Self::Stream) -> Result<Self> {
405		let mut ident = input.consume_kind(TokenKind::Ident)?;
406
407		if input.check(punct![::]) {
408			ident = input.upgrade_last(TokenKind::Ident, Token::module)?;
409			input.consume(punct![::])?;
410
411			Ok(Self::Namespaced(NamespacedIdentBuilder {
412				namespace: ident,
413				ident: Box::new(input.parse()?),
414			}))
415		} else {
416			Ok(Self::Leaf(ident))
417		}
418	}
419}
420
421impl IdentExprBuilder {
422	pub fn build(&self) -> IdentExpr {
423		match self {
424			IdentExprBuilder::Leaf(name) => IdentExpr::Leaf(name.clone()),
425			IdentExprBuilder::Namespaced(NamespacedIdentBuilder { namespace, ident }) => {
426				IdentExpr::Namespaced(NamespacedIdent {
427					namespace: namespace.clone(),
428					ident: Arc::new(ident.build()),
429				})
430			}
431		}
432	}
433}
434
435impl From<&IdentExpr> for IdentExprBuilder {
436	fn from(value: &IdentExpr) -> Self {
437		match value {
438			IdentExpr::Leaf(name) => IdentExprBuilder::Leaf(name.clone()),
439			IdentExpr::Namespaced(NamespacedIdent { namespace, ident }) => {
440				IdentExprBuilder::Namespaced(NamespacedIdentBuilder {
441					namespace: namespace.clone(),
442					ident: Box::new(ident.as_ref().into()),
443				})
444			}
445		}
446	}
447}
448
449impl Parse for IdentExpr {
450	type Stream = ParseStream;
451
452	fn parse(input: &mut Self::Stream) -> Result<Self> {
453		Ok(input.parse::<IdentExprBuilder>()?.build())
454	}
455}
456
457impl Parse for PostfixExpr {
458	type Stream = ParseStream;
459
460	fn parse(input: &mut Self::Stream) -> Result<Self> {
461		use TokenKind::*;
462
463		if input.check(punct![.]) {
464			let dot = input.next().unwrap();
465			let accessor = Accessor::Dot(dot);
466
467			let mut expr = input.parse::<PrimaryExprBuilder>()?;
468			if let Expr::Ident(ident) = expr.expr.as_mut() {
469				if let IdentExpr::Leaf(name) = ident {
470					*name = input.upgrade(name.clone(), Token::field)?;
471				} else {
472					// FIXME: This is pretty wildly inefficient
473					let mut builder = IdentExprBuilder::from(&*ident);
474					let mut ident_expr = &mut builder;
475					while let IdentExprBuilder::Namespaced(NamespacedIdentBuilder {
476						ident, ..
477					}) = ident_expr
478					{
479						ident_expr = ident.as_mut();
480					}
481					let IdentExprBuilder::Leaf(name) = ident_expr else {
482						unreachable!();
483					};
484					*name = input.upgrade(name.clone(), Token::field)?;
485					*ident = builder.build();
486				}
487			}
488
489			let postfix = match input.peek().map(|t| t.as_matchable()) {
490				Some((Punct, ".", _) | (Brace, "[", _)) => {
491					Some(Arc::new(input.parse::<PostfixExpr>()?))
492				}
493				_ => None,
494			};
495
496			Ok(Self {
497				accessor,
498				expr: Arc::new(Expr::Primary(expr.build())),
499				postfix,
500			})
501		} else {
502			let brace_open = input.consume(brace!["["])?;
503			let expr = input.parse::<Expr>()?;
504			let brace_close = input.consume(brace!["]"])?;
505
506			let postfix = match input.peek().map(|t| t.as_matchable()) {
507				Some((Punct, ".", _) | (Brace, "[", _)) => {
508					Some(Arc::new(input.parse::<PostfixExpr>()?))
509				}
510				_ => None,
511			};
512
513			Ok(Self {
514				accessor: Accessor::Index([brace_open, brace_close]),
515				expr: Arc::new(expr),
516				postfix,
517			})
518		}
519	}
520}
521
522// --- RecursiveDescent impl -------------------------------------------------------------
523
524impl RecursiveDescent for ParseStream {
525	type Token = Token;
526
527	fn assignment(&mut self) -> Result<Expr> {
528		let lhs = self.short_circuit_or()?;
529
530		// if self.check(operator![=]) {
531		if matches!(
532			self.peek().map(|t| t.as_matchable()),
533			Some((
534				TokenKind::Operator,
535				"+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "=",
536				_
537			))
538		) {
539			let op = self.next().unwrap();
540			let value = self.assignment()?;
541
542			match &lhs {
543				Expr::Primary(PrimaryExpr { expr, .. })
544					if matches!(expr.as_ref(), Expr::Ident(_)) =>
545				{
546					Ok(Expr::Assignment(BinaryExpr {
547						lhs: Arc::new(lhs),
548						op,
549						rhs: Arc::new(value),
550					}))
551				}
552				other => Err(SpannedError {
553					message: "Invalid assignment target".into(),
554					source: self.source(),
555					span: Some(other.span()),
556				}),
557			}
558		} else {
559			Ok(lhs)
560		}
561	}
562
563	fn short_circuit_or(&mut self) -> Result<Expr> {
564		self.binary(&[operator![||]], Self::short_circuit_and)
565	}
566
567	fn short_circuit_and(&mut self) -> Result<Expr> {
568		self.binary(&[operator![&&]], Self::inclusive_or)
569	}
570
571	fn inclusive_or(&mut self) -> Result<Expr> {
572		self.binary(&[operator![|]], Self::exclusive_or)
573	}
574
575	fn exclusive_or(&mut self) -> Result<Expr> {
576		self.binary(&[operator![^]], Self::and)
577	}
578
579	fn and(&mut self) -> Result<Expr> {
580		self.binary(&[operator![&]], Self::equality)
581	}
582
583	fn equality(&mut self) -> Result<Expr> {
584		self.binary(&[operator![==], operator![!=]], Self::relational)
585	}
586
587	fn relational(&mut self) -> Result<Expr> {
588		self.binary(
589			&[operator![<=], operator![>=], operator![<], operator![>]],
590			Self::shift,
591		)
592	}
593
594	fn shift(&mut self) -> Result<Expr> {
595		self.binary(&[operator![<<], operator![>>]], Self::additive)
596	}
597
598	fn additive(&mut self) -> Result<Expr> {
599		self.binary(&[operator!["+"], operator!["-"]], Self::multiplicative)
600	}
601
602	fn multiplicative(&mut self) -> Result<Expr> {
603		self.binary(&[operator![*], operator![/], operator![%]], Self::unary)
604	}
605
606	fn unary(&mut self) -> Result<Expr> {
607		if matches!(
608			self.peek().map(|t| t.as_matchable()),
609			Some((TokenKind::Operator, "-" | "!" | "~" | "*" | "&", _))
610		) {
611			let op = self.next().unwrap();
612			let expr = self.unary()?;
613
614			Ok(Expr::UnaryPre(UnaryPreExpr {
615				op,
616				expr: Arc::new(expr),
617			}))
618		} else {
619			let primary = Expr::Primary(self.parse::<PrimaryExprBuilder>()?.build());
620
621			if let Some((TokenKind::Operator, "++" | "--", _)) =
622				self.peek().map(|t| t.as_matchable())
623			{
624				let op = self.next().unwrap();
625
626				Ok(Expr::UnaryPost(UnaryPostExpr {
627					expr: Arc::new(primary),
628					op,
629				}))
630			} else {
631				Ok(primary)
632			}
633		}
634	}
635
636	fn binary(
637		&mut self,
638		operators: &[Self::Token],
639		operand_method: fn(&mut Self) -> Result<Expr>,
640	) -> Result<Expr> {
641		let mut expr = operand_method(self)?;
642
643		while operators.iter().any(|op| self.check(op.clone())) {
644			let op = self.next().unwrap();
645			let rhs = operand_method(self)?;
646
647			expr = Expr::Binary(BinaryExpr {
648				lhs: Arc::new(expr),
649				op,
650				rhs: Arc::new(rhs),
651			});
652		}
653
654		Ok(expr)
655	}
656}