wgsl_parser/decl/
struc.rs

1use std::sync::Arc;
2
3use gramatika::{Parse, ParseStreamer, Span, Spanned};
4
5use crate::{
6	common::{AttributeList, TypeDecl},
7	parser::ErrorRecoveringParseStream,
8	token::{brace, keyword, operator, punct, Token, TokenKind},
9	ParseStream,
10};
11
12use super::Decl;
13
14#[derive(Clone, DebugLisp)]
15pub struct StructDecl {
16	pub attributes: Option<AttributeList>,
17	pub storage: Token,
18	pub storage_modifier: Option<Token>,
19	pub name: Token,
20	pub body: StructBody,
21}
22
23#[derive(Clone, DebugLisp)]
24pub struct StructBody {
25	pub open_brace: Token,
26	pub fields: Arc<[Decl]>,
27	pub close_brace: Token,
28}
29
30#[derive(Clone, DebugLisp)]
31pub struct FieldDecl {
32	pub attributes: Option<AttributeList>,
33	pub name: Token,
34	pub ty: TypeDecl,
35	pub separator: Option<Token>,
36}
37
38impl Parse for StructDecl {
39	type Stream = ParseStream;
40
41	fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
42		let storage = input.consume(keyword![struct])?;
43
44		let storage_modifier = if input.check(operator![<]) {
45			input.consume(operator![<])?;
46			let modifier = input.consume_kind(TokenKind::Keyword)?;
47			input.consume(operator![>])?;
48
49			Some(modifier)
50		} else {
51			None
52		};
53
54		let name = input.consume_as(TokenKind::Ident, Token::struct_)?;
55		let body = input.parse()?;
56
57		Ok(Self {
58			attributes: None,
59			storage,
60			storage_modifier,
61			name,
62			body,
63		})
64	}
65}
66
67impl Spanned for StructDecl {
68	fn span(&self) -> Span {
69		self.storage.span().through(self.body.span())
70	}
71}
72
73impl Parse for StructBody {
74	type Stream = ParseStream;
75
76	fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
77		let open_brace = input.consume(brace!["{"])?;
78		let fields = input.parse_seq_with_finisher::<FieldDecl, _>(
79			|input| !input.check(brace!["}"]),
80			|_, field| Ok(Decl::Field(field)),
81		)?;
82		let close_brace = input.consume(brace!["}"])?;
83
84		Ok(Self {
85			open_brace,
86			fields: fields.into(),
87			close_brace,
88		})
89	}
90}
91
92impl Spanned for StructBody {
93	fn span(&self) -> Span {
94		self.open_brace.span().through(self.close_brace.span())
95	}
96}
97
98impl Parse for FieldDecl {
99	type Stream = ParseStream;
100
101	fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
102		let attributes = if input.check(punct!["@"]) {
103			Some(input.parse::<AttributeList>()?)
104		} else {
105			None
106		};
107		let name = input.consume_as(TokenKind::Ident, Token::field)?;
108		let ty = input.parse()?;
109
110		let separator = if !input.check(brace!("}")) {
111			Some(input.consume(punct![,])?)
112		} else {
113			None
114		};
115
116		Ok(Self {
117			attributes,
118			name,
119			ty,
120			separator,
121		})
122	}
123}
124
125impl Spanned for FieldDecl {
126	fn span(&self) -> Span {
127		let span_start = self
128			.attributes
129			.as_ref()
130			.and_then(|attrs| attrs.attributes.first().map(|attr| &attr.at_sign))
131			.unwrap_or(&self.name)
132			.span();
133
134		let span_end = match &self.separator {
135			Some(sep) => sep.span(),
136			None => self.ty.span(),
137		};
138
139		span_start.through(span_end)
140	}
141}