1use spade_ast::{AttributeList, Binding, Expression, Register, Statement};
2use spade_common::{
3 location_info::{lspan, AsLabel, Loc, WithLocation},
4 name::Visibility,
5};
6use spade_diagnostics::{diag_bail, Diagnostic};
7use spade_macros::trace_parser;
8
9use crate::{
10 error::Result, item_type::UnitKindLocal, lexer::TokenKind, peek_for, KeywordPeekingParser,
11 ParseStackEntry, Parser, Token,
12};
13
14pub(crate) struct BindingParser {}
15
16impl KeywordPeekingParser<Loc<Statement>> for BindingParser {
17 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
18 |kind| kind == &TokenKind::Let
19 }
20
21 fn parse(
22 &self,
23 parser: &mut Parser,
24 attributes: &AttributeList,
25 visibility: &Loc<Visibility>,
26 ) -> Result<Loc<Statement>> {
27 let start_token = parser.eat_unconditional()?;
28 parser.disallow_visibility(visibility, &start_token)?;
29
30 let (pattern, start_span) = parser.pattern()?.separate();
31
32 let ty = if parser.peek_and_eat(&TokenKind::Colon)?.is_some() {
33 Some(parser.type_spec()?)
34 } else {
35 None
36 };
37
38 parser.eat(&TokenKind::Assignment)?;
39 let (value, end_span) = parser.expression()?.separate();
40
41 Ok(Statement::Binding(Binding {
42 pattern,
43 ty,
44 value,
45 attrs: attributes.clone(),
46 })
47 .between(parser.file_id, &start_span, &end_span))
48 }
49}
50
51pub(crate) struct RegisterParser {}
52
53impl KeywordPeekingParser<Loc<Statement>> for RegisterParser {
54 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
55 |kind| kind == &TokenKind::Reg
56 }
57
58 fn parse(
59 &self,
60 parser: &mut Parser,
61 attributes: &AttributeList,
62 visibility: &Loc<Visibility>,
63 ) -> Result<Loc<Statement>> {
64 let start_token = parser.eat_unconditional()?;
65 parser.disallow_visibility(visibility, &start_token)?;
66
67 let cond = if parser.peek_kind(&TokenKind::OpenBracket)? {
70 Some(
71 parser
72 .surrounded(
73 &TokenKind::OpenBracket,
74 Parser::expression,
75 &TokenKind::CloseBracket,
76 )?
77 .0,
78 )
79 } else {
80 None
81 };
82
83 if parser.peek_kind(&TokenKind::Semi)? || parser.peek_kind(&TokenKind::Asterisk)? {
85 let count = if let Some(ast) = parser.peek_and_eat(&TokenKind::Asterisk)? {
86 match parser.type_expression() {
87 Ok(t) => Some(t),
88 Err(diag) => {
89 return Err(
90 diag.secondary_label(ast, "* is used to specify a register count")
91 )
92 }
93 }
94 } else {
95 None
96 };
97
98 let full_loc = if let Some(c) = &count {
99 ().between(parser.file_id, &start_token, &c.loc())
100 } else {
101 ().at(parser.file_id, &start_token)
102 };
103
104 return Ok(Statement::PipelineRegMarker(count, cond).at_loc(&full_loc));
105 }
106
107 parser
108 .unit_context
109 .allows_reg(().at(parser.file_id, &start_token.span()))?;
110
111 let (clock, _clock_paren_span) = parser.surrounded(
113 &TokenKind::OpenParen,
114 |s| s.expression().map(Some),
115 &TokenKind::CloseParen,
116 )?;
117
118 let clock = clock.unwrap();
121
122 let pattern = parser.pattern()?;
124
125 let value_type = if parser.peek_and_eat(&TokenKind::Colon)?.is_some() {
127 Some(parser.type_spec()?)
128 } else {
129 None
130 };
131
132 let reset = parser.register_reset()?;
134 let initial = parser.register_initial()?;
135 let reset = match (reset, parser.register_reset()?) {
137 (Some(first), None) => Some(first),
138 (None, Some(second)) => Some(second),
139 (Some(first), Some(second)) => {
140 return Err(Diagnostic::error(
141 ().between_locs(&second.0, &second.1),
142 "Multiple resets specified",
143 )
144 .primary_label("Second reset")
145 .secondary_label(().between_locs(&first.0, &first.1), "First reset"))
146 }
147 (None, None) => None,
148 };
149
150 parser.eat(&TokenKind::Assignment)?;
152 let (value, end_span) = parser.expression()?.separate();
153
154 let span = lspan(start_token.span).merge(end_span);
155 let result = Statement::Register(
156 Register {
157 pattern,
158 clock,
159 reset,
160 initial,
161 value,
162 value_type,
163 attributes: attributes.clone(),
164 }
165 .at(parser.file_id, &span),
166 )
167 .at(parser.file_id, &span);
168 Ok(result)
169 }
170}
171
172impl<'a> Parser<'a> {
173 #[trace_parser]
174 pub fn register_reset_definition(&mut self) -> Result<(Loc<Expression>, Loc<Expression>)> {
175 let condition = self.expression()?;
176 self.eat(&TokenKind::Colon)?;
177 let value = self.expression()?;
178
179 Ok((condition, value))
180 }
181
182 #[trace_parser]
183 pub fn register_reset(&mut self) -> Result<Option<(Loc<Expression>, Loc<Expression>)>> {
184 peek_for!(self, &TokenKind::Reset);
185 let (reset, _) = self.surrounded(
186 &TokenKind::OpenParen,
187 |s| s.register_reset_definition().map(Some),
188 &TokenKind::CloseParen,
189 )?;
190 Ok(Some(reset.unwrap()))
192 }
193
194 #[trace_parser]
195 pub fn register_initial(&mut self) -> Result<Option<Loc<Expression>>> {
196 peek_for!(self, &TokenKind::Initial);
197 let (reset, _) = self.surrounded(
198 &TokenKind::OpenParen,
199 Self::expression,
200 &TokenKind::CloseParen,
201 )?;
202 Ok(Some(reset))
203 }
204}
205
206pub(crate) struct DeclParser {}
207
208impl KeywordPeekingParser<Loc<Statement>> for DeclParser {
209 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
210 |kind| kind == &TokenKind::Decl
211 }
212
213 fn parse(
214 &self,
215 parser: &mut Parser,
216 attributes: &AttributeList,
217 visibility: &Loc<Visibility>,
218 ) -> Result<Loc<Statement>> {
219 let start_token = parser.eat_unconditional()?;
220 parser.disallow_attributes(attributes, &start_token)?;
221 parser.disallow_visibility(visibility, &start_token)?;
222
223 let mut identifiers = vec![];
224 while parser.peek_cond(|t| t.is_identifier(), "expected identifier")? {
225 identifiers.push(parser.identifier()?);
226
227 if parser.peek_and_eat(&TokenKind::Comma)?.is_none() {
228 break;
229 }
230 }
231
232 if identifiers.is_empty() {
233 return Err(Diagnostic::error(start_token.loc(), "empty decl statement")
234 .primary_label("this decl does not declare anything"));
235 }
236
237 let last_ident = identifiers.last().unwrap().clone();
238
239 Ok(Statement::Declaration(identifiers).between(
240 parser.file_id,
241 &start_token.span,
242 &last_ident,
243 ))
244 }
245}
246
247pub(crate) struct LabelParser {}
248
249impl KeywordPeekingParser<Loc<Statement>> for LabelParser {
250 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
251 |kind| matches!(kind, TokenKind::Label(_))
252 }
253
254 fn parse(
255 &self,
256 parser: &mut Parser,
257 attributes: &AttributeList,
258 visibility: &Loc<Visibility>,
259 ) -> Result<Loc<Statement>> {
260 let tok @ Token {
261 kind: TokenKind::Label(l),
262 ..
263 } = &parser.eat_unconditional()?
264 else {
265 diag_bail!(
266 parser.peek()?,
267 "Label parser was called but it did not get a label"
268 )
269 };
270 parser.disallow_attributes(attributes, &tok)?;
271 parser.disallow_visibility(visibility, &tok)?;
272
273 Ok(Statement::Label(l.clone().at(parser.file_id, &tok.span)).at(parser.file_id, &tok.span))
274 }
275}
276
277pub(crate) struct AssertParser {}
278
279impl KeywordPeekingParser<Loc<Statement>> for AssertParser {
280 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
281 |kind| kind == &TokenKind::Assert
282 }
283
284 fn parse(
285 &self,
286 parser: &mut Parser,
287 attributes: &AttributeList,
288 visibility: &Loc<Visibility>,
289 ) -> Result<Loc<Statement>> {
290 let tok = parser.eat_unconditional()?;
291 parser.disallow_attributes(attributes, &tok)?;
292 parser.disallow_visibility(visibility, &tok)?;
293
294 let expr = parser.expression()?;
295
296 Ok(Statement::Assert(expr.clone()).between(parser.file_id, &tok.span, &expr))
297 }
298}
299
300pub(crate) struct SetParser {}
301
302impl KeywordPeekingParser<Loc<Statement>> for SetParser {
303 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
304 |kind| kind == &TokenKind::Set
305 }
306
307 fn parse(
308 &self,
309 parser: &mut Parser,
310 attributes: &AttributeList,
311 visibility: &Loc<Visibility>,
312 ) -> Result<Loc<Statement>> {
313 let tok = parser.eat_unconditional()?;
314 parser.disallow_attributes(attributes, &tok)?;
315 parser.disallow_visibility(visibility, &tok)?;
316
317 let target = parser.expression()?;
318
319 parser.eat(&TokenKind::Assignment)?;
320
321 let value = parser.expression()?;
322
323 Ok(Statement::Set {
324 target,
325 value: value.clone(),
326 }
327 .between(parser.file_id, &tok.span, &value))
328 }
329}