wgsl_parser/decl/
struc.rs1use 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}