wac_parser/ast/
expr.rs

1use super::{
2    parse_delimited, parse_token, Ident, Lookahead, PackageName, Parse, ParseResult, Peek,
3};
4use crate::lexer::{Lexer, Token};
5use miette::SourceSpan;
6use serde::Serialize;
7
8/// Represents an expression in the AST.
9#[derive(Debug, Clone, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct Expr<'a> {
12    /// The span of the entire expression.
13    pub span: SourceSpan,
14    /// The primary expression.
15    pub primary: PrimaryExpr<'a>,
16    /// The postfix expressions
17    pub postfix: Vec<PostfixExpr<'a>>,
18}
19
20impl<'a> Parse<'a> for Expr<'a> {
21    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
22        let primary = PrimaryExpr::parse(lexer)?;
23
24        // Currently, only the access expressions are supported for postfix expressions.
25        // As they have the same precedence, we don't need to perform climbing.
26        let mut postfix = Vec::new();
27        while let Some((Ok(token), _)) = lexer.peek() {
28            match token {
29                Token::Dot => {
30                    postfix.push(PostfixExpr::Access(Parse::parse(lexer)?));
31                }
32                Token::OpenBracket => {
33                    postfix.push(PostfixExpr::NamedAccess(Parse::parse(lexer)?));
34                }
35                _ => break,
36            }
37        }
38
39        let start = primary.span();
40        let len = postfix.last().map_or(start.len(), |p| {
41            p.span().offset() + p.span().len() - start.offset()
42        });
43
44        Ok(Self {
45            span: SourceSpan::new(start.offset().into(), len),
46            primary,
47            postfix,
48        })
49    }
50}
51
52/// Represents a primary expression in the AST.
53#[derive(Debug, Clone, Serialize)]
54#[serde(rename_all = "camelCase")]
55pub enum PrimaryExpr<'a> {
56    /// A new expression.
57    New(NewExpr<'a>),
58    /// A nested expression.
59    Nested(NestedExpr<'a>),
60    /// An identifier.
61    Ident(Ident<'a>),
62}
63
64impl PrimaryExpr<'_> {
65    /// Gets the span of the primary expression.
66    pub fn span(&self) -> SourceSpan {
67        match self {
68            PrimaryExpr::New(new) => new.span,
69            PrimaryExpr::Nested(nested) => nested.span,
70            PrimaryExpr::Ident(ident) => ident.span,
71        }
72    }
73}
74
75impl<'a> Parse<'a> for PrimaryExpr<'a> {
76    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
77        let mut lookahead = Lookahead::new(lexer);
78        if NewExpr::peek(&mut lookahead) {
79            Ok(Self::New(Parse::parse(lexer)?))
80        } else if NestedExpr::peek(&mut lookahead) {
81            Ok(Self::Nested(Parse::parse(lexer)?))
82        } else if Ident::peek(&mut lookahead) {
83            Ok(Self::Ident(Parse::parse(lexer)?))
84        } else {
85            Err(lookahead.error())
86        }
87    }
88}
89
90/// Represents a new expression in the AST.
91#[derive(Debug, Clone, Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct NewExpr<'a> {
94    /// The span of the new expression.
95    pub span: SourceSpan,
96    /// The package name in the expression.
97    pub package: PackageName<'a>,
98    /// The instantiation arguments in the expression.
99    pub arguments: Vec<InstantiationArgument<'a>>,
100}
101
102impl<'a> Parse<'a> for NewExpr<'a> {
103    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
104        let start = parse_token(lexer, Token::NewKeyword)?;
105        let package = PackageName::parse(lexer)?;
106        parse_token(lexer, Token::OpenBrace)?;
107        let arguments = parse_delimited(lexer, Token::CloseBrace, true)?;
108        let end = parse_token(lexer, Token::CloseBrace)?;
109        Ok(Self {
110            span: SourceSpan::new(
111                start.offset().into(),
112                (end.offset() + end.len()) - start.offset(),
113            ),
114            package,
115            arguments,
116        })
117    }
118}
119
120impl Peek for NewExpr<'_> {
121    fn peek(lookahead: &mut Lookahead) -> bool {
122        lookahead.peek(Token::NewKeyword)
123    }
124}
125
126/// Represents an instantiation argument in the AST.
127#[derive(Debug, Clone, Serialize)]
128#[serde(rename_all = "camelCase")]
129pub enum InstantiationArgument<'a> {
130    /// The argument name is inferred.
131    Inferred(Ident<'a>),
132    /// The argument is a spread of an instance.
133    Spread(Ident<'a>),
134    /// The argument is a named instantiation argument.
135    Named(NamedInstantiationArgument<'a>),
136    /// Fill remaining arguments with implicit imports.
137    Fill(SourceSpan),
138}
139
140impl<'a> Parse<'a> for InstantiationArgument<'a> {
141    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
142        let mut lookahead = Lookahead::new(lexer);
143        if lookahead.peek(Token::Ellipsis) {
144            // This is a spread of an instance or a fill.
145            let span = parse_token(lexer, Token::Ellipsis)?;
146            match lexer.peek() {
147                Some((Ok(Token::Comma), _)) | Some((Ok(Token::CloseBrace), _)) => {
148                    // This is a fill.
149                    Ok(Self::Fill(span))
150                }
151                _ => {
152                    // This is a spread of an instance.
153                    Ok(Self::Spread(Parse::parse(lexer)?))
154                }
155            }
156        } else if NamedInstantiationArgument::peek(&mut lookahead) {
157            // Peek again to see if this is really a named instantiation argument or
158            // an inferred argument.
159            if let Some((Ok(Token::Colon), _)) = lexer.peek2() {
160                Ok(Self::Named(Parse::parse(lexer)?))
161            } else {
162                Ok(Self::Inferred(Parse::parse(lexer)?))
163            }
164        } else {
165            Err(lookahead.error())
166        }
167    }
168}
169
170impl Peek for InstantiationArgument<'_> {
171    fn peek(lookahead: &mut Lookahead) -> bool {
172        lookahead.peek(Token::Ellipsis) | NamedInstantiationArgument::peek(lookahead)
173    }
174}
175
176/// Represents a named instantiation argument in the AST.
177#[derive(Debug, Clone, Serialize)]
178#[serde(rename_all = "camelCase")]
179pub struct NamedInstantiationArgument<'a> {
180    /// The name of the argument.
181    pub name: InstantiationArgumentName<'a>,
182    /// The expression in the argument.
183    pub expr: Expr<'a>,
184}
185
186impl<'a> Parse<'a> for NamedInstantiationArgument<'a> {
187    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
188        let name = Parse::parse(lexer)?;
189        parse_token(lexer, Token::Colon)?;
190        let expr = Parse::parse(lexer)?;
191        Ok(Self { name, expr })
192    }
193}
194
195impl Peek for NamedInstantiationArgument<'_> {
196    fn peek(lookahead: &mut Lookahead) -> bool {
197        InstantiationArgumentName::peek(lookahead)
198    }
199}
200
201/// Represents the argument name in an instantiation argument in the AST.
202#[derive(Debug, Clone, Serialize)]
203#[serde(rename_all = "camelCase")]
204pub enum InstantiationArgumentName<'a> {
205    /// The argument name is an identifier.
206    Ident(Ident<'a>),
207    /// The argument name is a string.
208    String(super::String<'a>),
209}
210
211impl InstantiationArgumentName<'_> {
212    /// Gets the string value of the instantiation argument name.
213    pub fn as_str(&self) -> &str {
214        match self {
215            Self::Ident(ident) => ident.string,
216            Self::String(string) => string.value,
217        }
218    }
219}
220
221impl<'a> Parse<'a> for InstantiationArgumentName<'a> {
222    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
223        let mut lookahead = Lookahead::new(lexer);
224        if Ident::peek(&mut lookahead) {
225            Ok(Self::Ident(Parse::parse(lexer)?))
226        } else if super::String::peek(&mut lookahead) {
227            Ok(Self::String(Parse::parse(lexer)?))
228        } else {
229            Err(lookahead.error())
230        }
231    }
232}
233
234impl Peek for InstantiationArgumentName<'_> {
235    fn peek(lookahead: &mut Lookahead) -> bool {
236        Ident::peek(lookahead) || super::String::peek(lookahead)
237    }
238}
239
240impl InstantiationArgumentName<'_> {
241    /// Gets the span of the instantiation argument name.
242    pub fn span(&self) -> SourceSpan {
243        match self {
244            Self::Ident(ident) => ident.span,
245            Self::String(string) => string.span,
246        }
247    }
248}
249
250/// Represents a nested expression in the AST.
251#[derive(Debug, Clone, Serialize)]
252#[serde(rename_all = "camelCase")]
253pub struct NestedExpr<'a> {
254    /// The span of the nested expression.
255    pub span: SourceSpan,
256    /// The inner expression.
257    pub inner: Box<Expr<'a>>,
258}
259
260impl<'a> Parse<'a> for NestedExpr<'a> {
261    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
262        let start = parse_token(lexer, Token::OpenParen)?;
263        let inner = Box::new(Parse::parse(lexer)?);
264        let end = parse_token(lexer, Token::CloseParen)?;
265        Ok(Self {
266            span: SourceSpan::new(
267                start.offset().into(),
268                (end.offset() + end.len()) - start.offset(),
269            ),
270            inner,
271        })
272    }
273}
274
275impl Peek for NestedExpr<'_> {
276    fn peek(lookahead: &mut Lookahead) -> bool {
277        lookahead.peek(Token::OpenParen)
278    }
279}
280
281/// Represents a postfix expression in the AST.
282#[derive(Debug, Clone, Serialize)]
283#[serde(rename_all = "camelCase")]
284pub enum PostfixExpr<'a> {
285    /// The postfix expression is an access expression.
286    Access(AccessExpr<'a>),
287    /// The postfix expression is a named access expression.
288    NamedAccess(NamedAccessExpr<'a>),
289}
290
291impl PostfixExpr<'_> {
292    /// Gets the span of the postfix expression.
293    pub fn span(&self) -> SourceSpan {
294        match self {
295            PostfixExpr::Access(access) => access.span,
296            PostfixExpr::NamedAccess(access) => access.span,
297        }
298    }
299}
300
301/// Represents an access expression in the AST.
302#[derive(Debug, Clone, Serialize)]
303#[serde(rename_all = "camelCase")]
304pub struct AccessExpr<'a> {
305    /// The span of the access expression.
306    pub span: SourceSpan,
307    /// The identifier in the expression.
308    pub id: Ident<'a>,
309}
310
311impl<'a> Parse<'a> for AccessExpr<'a> {
312    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
313        let start = parse_token(lexer, Token::Dot)?;
314        let id: Ident = Parse::parse(lexer)?;
315        Ok(Self {
316            span: SourceSpan::new(
317                start.offset().into(),
318                id.span.offset() - start.offset() + id.span.len(),
319            ),
320            id,
321        })
322    }
323}
324
325impl Peek for AccessExpr<'_> {
326    fn peek(lookahead: &mut Lookahead) -> bool {
327        lookahead.peek(Token::Dot)
328    }
329}
330
331/// Represents a named access expression in the AST.
332#[derive(Debug, Clone, Serialize)]
333#[serde(rename_all = "camelCase")]
334pub struct NamedAccessExpr<'a> {
335    /// The span of the access expression.
336    pub span: SourceSpan,
337    /// The name string in the expression.
338    pub string: super::String<'a>,
339}
340
341impl<'a> Parse<'a> for NamedAccessExpr<'a> {
342    fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
343        let opening = parse_token(lexer, Token::OpenBracket)?;
344        let string = Parse::parse(lexer)?;
345        let closing = parse_token(lexer, Token::CloseBracket)?;
346        Ok(Self {
347            span: SourceSpan::new(
348                opening.offset().into(),
349                (closing.offset() + closing.len()) - opening.offset(),
350            ),
351            string,
352        })
353    }
354}
355
356impl Peek for NamedAccessExpr<'_> {
357    fn peek(lookahead: &mut Lookahead) -> bool {
358        lookahead.peek(Token::OpenBracket)
359    }
360}