1use spade_ast::{AttributeList, Binding, Expression, Register, Statement, token::TokenKind};
2use spade_common::{
3 location_info::{AsLabel, Loc, WithLocation, lspan},
4 name::Visibility,
5};
6use spade_diagnostics::{Diagnostic, diag_bail};
7use spade_macros::trace_parser;
8
9use crate::{
10 KeywordPeekingParser, ParseStackEntry, Parser, Token, error::Result, item_type::UnitKindLocal,
11 peek_for,
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(false)?)
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(false)?)
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.clone()).merge(end_span);
155 let result = Statement::Register(
156 Register {
157 keyword: ().at(parser.file_id(), &start_token),
158 pattern,
159 clock,
160 reset,
161 initial,
162 value,
163 value_type,
164 attributes: attributes.clone(),
165 }
166 .at(parser.file_id(), &span),
167 )
168 .at(parser.file_id(), &span);
169 Ok(result)
170 }
171}
172
173impl<'a> Parser<'a> {
174 #[trace_parser]
175 pub fn register_reset_definition(&mut self) -> Result<(Loc<Expression>, Loc<Expression>)> {
176 let condition = self.expression()?;
177 self.eat(&TokenKind::Colon)?;
178 let value = self.expression()?;
179
180 Ok((condition, value))
181 }
182
183 #[trace_parser]
184 pub fn register_reset(&mut self) -> Result<Option<(Loc<Expression>, Loc<Expression>)>> {
185 peek_for!(self, &TokenKind::Reset);
186 let (reset, _) = self.surrounded(
187 &TokenKind::OpenParen,
188 |s| s.register_reset_definition().map(Some),
189 &TokenKind::CloseParen,
190 )?;
191 Ok(Some(reset.unwrap()))
193 }
194
195 #[trace_parser]
196 pub fn register_initial(&mut self) -> Result<Option<Loc<Expression>>> {
197 peek_for!(self, &TokenKind::Initial);
198 let (reset, _) = self.surrounded(
199 &TokenKind::OpenParen,
200 Self::expression,
201 &TokenKind::CloseParen,
202 )?;
203 Ok(Some(reset))
204 }
205}
206
207pub(crate) struct DeclParser {}
208
209impl KeywordPeekingParser<Loc<Statement>> for DeclParser {
210 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
211 |kind| kind == &TokenKind::Decl
212 }
213
214 fn parse(
215 &self,
216 parser: &mut Parser,
217 attributes: &AttributeList,
218 visibility: &Loc<Visibility>,
219 ) -> Result<Loc<Statement>> {
220 let start_token = parser.eat_unconditional()?;
221 parser.disallow_attributes(attributes, &start_token)?;
222 parser.disallow_visibility(visibility, &start_token)?;
223
224 let mut identifiers = vec![];
225 while parser.peek_cond(|t| t.is_identifier(), "expected identifier")? {
226 identifiers.push(parser.identifier()?);
227
228 if parser.peek_and_eat(&TokenKind::Comma)?.is_none() {
229 break;
230 }
231 }
232
233 if identifiers.is_empty() {
234 return Err(Diagnostic::error(start_token.loc(), "empty decl statement")
235 .primary_label("this decl does not declare anything"));
236 }
237
238 let last_ident = identifiers.last().unwrap().clone();
239
240 Ok(Statement::Declaration(identifiers).between(
241 parser.file_id(),
242 &start_token.span,
243 &last_ident,
244 ))
245 }
246}
247
248pub(crate) struct LabelParser {}
249
250impl KeywordPeekingParser<Loc<Statement>> for LabelParser {
251 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
252 |kind| matches!(kind, TokenKind::Label(_))
253 }
254
255 fn parse(
256 &self,
257 parser: &mut Parser,
258 attributes: &AttributeList,
259 visibility: &Loc<Visibility>,
260 ) -> Result<Loc<Statement>> {
261 let tok @ Token {
262 kind: TokenKind::Label(l),
263 ..
264 } = &parser.eat_unconditional()?
265 else {
266 diag_bail!(
267 parser.peek()?,
268 "Label parser was called but it did not get a label"
269 )
270 };
271 parser.disallow_attributes(attributes, &tok)?;
272 parser.disallow_visibility(visibility, &tok)?;
273
274 Ok(Statement::Label(l.clone().at(parser.file_id(), &tok.span))
275 .at(parser.file_id(), &tok.span))
276 }
277}
278
279pub(crate) struct AssertParser {}
280
281impl KeywordPeekingParser<Loc<Statement>> for AssertParser {
282 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
283 |kind| kind == &TokenKind::Assert
284 }
285
286 fn parse(
287 &self,
288 parser: &mut Parser,
289 attributes: &AttributeList,
290 visibility: &Loc<Visibility>,
291 ) -> Result<Loc<Statement>> {
292 let tok = parser.eat_unconditional()?;
293 parser.disallow_attributes(attributes, &tok)?;
294 parser.disallow_visibility(visibility, &tok)?;
295
296 let expr = parser.expression()?;
297
298 Ok(Statement::Assert(expr.clone()).between(parser.file_id(), &tok.span, &expr))
299 }
300}
301
302pub(crate) struct SetParser {}
303
304impl KeywordPeekingParser<Loc<Statement>> for SetParser {
305 fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
306 |kind| kind == &TokenKind::Set
307 }
308
309 fn parse(
310 &self,
311 parser: &mut Parser,
312 attributes: &AttributeList,
313 visibility: &Loc<Visibility>,
314 ) -> Result<Loc<Statement>> {
315 let tok = parser.eat_unconditional()?;
316 parser.disallow_attributes(attributes, &tok)?;
317 parser.disallow_visibility(visibility, &tok)?;
318
319 let target = parser.expression()?;
320
321 parser.eat(&TokenKind::Assignment)?;
322
323 let value = parser.expression()?;
324
325 Ok(Statement::Set {
326 target,
327 value: value.clone(),
328 }
329 .between(parser.file_id(), &tok.span, &value))
330 }
331}