spade_parser/
statements.rs

1use spade_ast::{AttributeList, Binding, Expression, Register, Statement};
2use spade_common::location_info::{lspan, AsLabel, Loc, WithLocation};
3use spade_diagnostics::Diagnostic;
4use spade_macros::trace_parser;
5
6use crate::{
7    error::Result, item_type::UnitKindLocal, lexer::TokenKind, peek_for, KeywordPeekingParser,
8    ParseStackEntry, Parser,
9};
10
11pub(crate) struct BindingParser {}
12
13impl KeywordPeekingParser<Loc<Statement>> for BindingParser {
14    fn leading_tokens(&self) -> Vec<TokenKind> {
15        vec![TokenKind::Let]
16    }
17
18    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
19        let _ = parser.eat_unconditional()?;
20
21        let (pattern, start_span) = parser.pattern()?.separate();
22
23        let ty = if parser.peek_and_eat(&TokenKind::Colon)?.is_some() {
24            Some(parser.type_spec()?)
25        } else {
26            None
27        };
28
29        parser.eat(&TokenKind::Assignment)?;
30        let (value, end_span) = parser.expression()?.separate();
31
32        Ok(Statement::Binding(Binding {
33            pattern,
34            ty,
35            value,
36            attrs: attributes.clone(),
37        })
38        .between(parser.file_id, &start_span, &end_span))
39    }
40}
41
42pub(crate) struct RegisterParser {}
43
44impl KeywordPeekingParser<Loc<Statement>> for RegisterParser {
45    fn leading_tokens(&self) -> Vec<TokenKind> {
46        vec![TokenKind::Reg]
47    }
48
49    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
50        let start_token = parser.eat_unconditional()?;
51
52        // NOTE: It might be nicer to use () but that complicates the compiler slightly more
53        // annoying to write, so I'll use [] initially as a proof of concept
54        let cond = if parser.peek_kind(&TokenKind::OpenBracket)? {
55            Some(
56                parser
57                    .surrounded(
58                        &TokenKind::OpenBracket,
59                        Parser::expression,
60                        &TokenKind::CloseBracket,
61                    )?
62                    .0,
63            )
64        } else {
65            None
66        };
67
68        // If this is a reg marker for a pipeline
69        if parser.peek_kind(&TokenKind::Semi)? || parser.peek_kind(&TokenKind::Asterisk)? {
70            let count = if let Some(ast) = parser.peek_and_eat(&TokenKind::Asterisk)? {
71                match parser.type_expression() {
72                    Ok(t) => Some(t),
73                    Err(diag) => {
74                        return Err(
75                            diag.secondary_label(ast, "* is used to specify a register count")
76                        )
77                    }
78                }
79            } else {
80                None
81            };
82
83            let full_loc = if let Some(c) = &count {
84                ().between(parser.file_id, &start_token, &c.loc())
85            } else {
86                ().at(parser.file_id, &start_token)
87            };
88
89            return Ok(Statement::PipelineRegMarker(count, cond).at_loc(&full_loc));
90        }
91
92        parser
93            .unit_context
94            .allows_reg(().at(parser.file_id, &start_token.span()))?;
95
96        // Clock selection
97        let (clock, _clock_paren_span) = parser.surrounded(
98            &TokenKind::OpenParen,
99            |s| s.expression().map(Some),
100            &TokenKind::CloseParen,
101        )?;
102
103        // Identifier parsing cannot fail since we map it into a Some. Therefore,
104        // unwrap is safe
105        let clock = clock.unwrap();
106
107        // Name
108        let pattern = parser.pattern()?;
109
110        // Optional type
111        let value_type = if parser.peek_and_eat(&TokenKind::Colon)?.is_some() {
112            Some(parser.type_spec()?)
113        } else {
114            None
115        };
116
117        // Optional reset
118        let reset = parser.register_reset()?;
119        let initial = parser.register_initial()?;
120        // Try parsing reset again, if we find two resets, error out
121        let reset = match (reset, parser.register_reset()?) {
122            (Some(first), None) => Some(first),
123            (None, Some(second)) => Some(second),
124            (Some(first), Some(second)) => {
125                return Err(Diagnostic::error(
126                    ().between_locs(&second.0, &second.1),
127                    "Multiple resets specified",
128                )
129                .primary_label("Second reset")
130                .secondary_label(().between_locs(&first.0, &first.1), "First reset"))
131            }
132            (None, None) => None,
133        };
134
135        // Value
136        parser.eat(&TokenKind::Assignment)?;
137        let (value, end_span) = parser.expression()?.separate();
138
139        let span = lspan(start_token.span).merge(end_span);
140        let result = Statement::Register(
141            Register {
142                pattern,
143                clock,
144                reset,
145                initial,
146                value,
147                value_type,
148                attributes: attributes.clone(),
149            }
150            .at(parser.file_id, &span),
151        )
152        .at(parser.file_id, &span);
153        Ok(result)
154    }
155}
156
157impl<'a> Parser<'a> {
158    #[trace_parser]
159    pub fn register_reset_definition(&mut self) -> Result<(Loc<Expression>, Loc<Expression>)> {
160        let condition = self.expression()?;
161        self.eat(&TokenKind::Colon)?;
162        let value = self.expression()?;
163
164        Ok((condition, value))
165    }
166
167    #[trace_parser]
168    pub fn register_reset(&mut self) -> Result<Option<(Loc<Expression>, Loc<Expression>)>> {
169        peek_for!(self, &TokenKind::Reset);
170        let (reset, _) = self.surrounded(
171            &TokenKind::OpenParen,
172            |s| s.register_reset_definition().map(Some),
173            &TokenKind::CloseParen,
174        )?;
175        // NOTE: Safe unwrap, register_reset_definition can not fail
176        Ok(Some(reset.unwrap()))
177    }
178
179    #[trace_parser]
180    pub fn register_initial(&mut self) -> Result<Option<Loc<Expression>>> {
181        peek_for!(self, &TokenKind::Initial);
182        let (reset, _) = self.surrounded(
183            &TokenKind::OpenParen,
184            Self::expression,
185            &TokenKind::CloseParen,
186        )?;
187        Ok(Some(reset))
188    }
189}
190
191pub(crate) struct DeclParser {}
192
193impl KeywordPeekingParser<Loc<Statement>> for DeclParser {
194    fn leading_tokens(&self) -> Vec<TokenKind> {
195        vec![TokenKind::Decl]
196    }
197
198    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
199        let start_token = parser.eat_unconditional()?;
200        parser.disallow_attributes(attributes, &start_token)?;
201
202        let mut identifiers = vec![];
203        while parser.peek_cond(|t| t.is_identifier(), "expected identifier")? {
204            identifiers.push(parser.identifier()?);
205
206            if parser.peek_and_eat(&TokenKind::Comma)?.is_none() {
207                break;
208            }
209        }
210
211        if identifiers.is_empty() {
212            return Err(Diagnostic::error(start_token.loc(), "empty decl statement")
213                .primary_label("this decl does not declare anything"));
214        }
215
216        let last_ident = identifiers.last().unwrap().clone();
217
218        Ok(Statement::Declaration(identifiers).between(
219            parser.file_id,
220            &start_token.span,
221            &last_ident,
222        ))
223    }
224}
225
226pub(crate) struct LabelParser {}
227
228impl KeywordPeekingParser<Loc<Statement>> for LabelParser {
229    fn leading_tokens(&self) -> Vec<TokenKind> {
230        vec![TokenKind::SingleQuote]
231    }
232
233    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
234        let tok = parser.eat_unconditional()?;
235        parser.disallow_attributes(attributes, &tok)?;
236
237        let name = parser.identifier()?;
238        Ok(Statement::Label(name.clone()).between(parser.file_id, &tok.span, &name))
239    }
240}
241
242pub(crate) struct AssertParser {}
243
244impl KeywordPeekingParser<Loc<Statement>> for AssertParser {
245    fn leading_tokens(&self) -> Vec<TokenKind> {
246        vec![TokenKind::Assert]
247    }
248
249    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
250        let tok = parser.eat_unconditional()?;
251        parser.disallow_attributes(attributes, &tok)?;
252
253        let expr = parser.expression()?;
254
255        Ok(Statement::Assert(expr.clone()).between(parser.file_id, &tok.span, &expr))
256    }
257}
258
259pub(crate) struct SetParser {}
260
261impl KeywordPeekingParser<Loc<Statement>> for SetParser {
262    fn leading_tokens(&self) -> Vec<TokenKind> {
263        vec![TokenKind::Set]
264    }
265
266    fn parse(&self, parser: &mut Parser, attributes: &AttributeList) -> Result<Loc<Statement>> {
267        let tok = parser.eat_unconditional()?;
268        parser.disallow_attributes(attributes, &tok)?;
269
270        let target = parser.expression()?;
271
272        parser.eat(&TokenKind::Assignment)?;
273
274        let value = parser.expression()?;
275
276        Ok(Statement::Set {
277            target,
278            value: value.clone(),
279        }
280        .between(parser.file_id, &tok.span, &value))
281    }
282}