sqparse/parser/
expression.rs

1use crate::ast::{
2    ArrayExpression, BinaryExpression, CallExpression, ClassExpression, CommaExpression,
3    DelegateExpression, ExpectExpression, Expression, FunctionExpression, IndexExpression,
4    LiteralExpression, ParensExpression, PostfixExpression, Precedence, PrefixExpression,
5    PropertyExpression, RootVarExpression, TableExpression, TernaryExpression, VarExpression,
6    VectorExpression,
7};
8use crate::parser::array::array_value;
9use crate::parser::class::class_definition;
10use crate::parser::function::function_definition;
11use crate::parser::identifier::{identifier, method_identifier};
12use crate::parser::operator::{binary_operator, postfix_operator, prefix_operator};
13use crate::parser::parse_result_ext::ParseResultExt;
14use crate::parser::table::table_slot;
15use crate::parser::token_list::TokenList;
16use crate::parser::token_list_ext::TokenListExt;
17use crate::parser::type_::type_;
18use crate::parser::ParseResult;
19use crate::token::{TerminalToken, TokenType};
20use crate::{ContextType, ParseErrorType};
21
22pub fn expression(tokens: TokenList, precedence: Precedence) -> ParseResult<Box<Expression>> {
23    let (mut next_tokens, mut value) = value(tokens)?;
24
25    loop {
26        let mut value_container = Some(value);
27        match operator(next_tokens, precedence, ExpressionRef(&mut value_container))
28            .with_context_from(ContextType::Expression, tokens)
29            .maybe(next_tokens)?
30        {
31            (new_tokens, Some(new_value)) => {
32                next_tokens = new_tokens;
33                value = new_value;
34            }
35            (new_tokens, None) => return Ok((new_tokens, value_container.unwrap())),
36        }
37    }
38}
39
40fn value(tokens: TokenList) -> ParseResult<Box<Expression>> {
41    function(tokens)
42        .map_val(Expression::Function)
43        .or_try(|| parens(tokens).map_val(Expression::Parens))
44        .or_try(|| literal(tokens).map_val(Expression::Literal))
45        .or_try(|| var(tokens).map_val(Expression::Var))
46        .or_try(|| root_var(tokens).map_val(Expression::RootVar))
47        .or_try(|| table(tokens).map_val(Expression::Table))
48        .or_try(|| class(tokens).map_val(Expression::Class))
49        .or_try(|| array(tokens).map_val(Expression::Array))
50        .or_try(|| vector(tokens).map_val(Expression::Vector))
51        .or_try(|| prefix(tokens).map_val(Expression::Prefix))
52        .or_try(|| delegate(tokens).map_val(Expression::Delegate))
53        .or_try(|| expect(tokens).map_val(Expression::Expect))
54        .or_error(|| tokens.error(ParseErrorType::ExpectedValue))
55        .map_val(Box::new)
56}
57
58pub fn function(tokens: TokenList) -> ParseResult<FunctionExpression> {
59    type_(tokens)
60        .not_line_ending()
61        .maybe(tokens)
62        .and_then(|(tokens, return_type)| {
63            tokens
64                .terminal(TerminalToken::Function)
65                .map_val(|function| (return_type, function))
66        })
67        .determines(|tokens, (return_type, function)| {
68            function_definition(tokens).map_val(|definition| FunctionExpression {
69                return_type,
70                function,
71                definition,
72            })
73        })
74        .with_context_from(ContextType::FunctionLiteral, tokens)
75}
76
77pub fn parens(tokens: TokenList) -> ParseResult<ParensExpression> {
78    tokens
79        .terminal(TerminalToken::OpenBracket)
80        .determines_and_opens(
81            ContextType::Expression,
82            |tokens| tokens.terminal(TerminalToken::CloseBracket),
83            |tokens, open, close| {
84                expression(tokens, Precedence::None).map_val(|value| ParensExpression {
85                    open,
86                    value,
87                    close,
88                })
89            },
90        )
91}
92
93pub fn literal(tokens: TokenList) -> ParseResult<LiteralExpression> {
94    if let Some((tokens, item)) = tokens.split_first() {
95        if let TokenType::Literal(literal) = item.token.ty {
96            return Ok((
97                tokens,
98                LiteralExpression {
99                    literal,
100                    token: &item.token,
101                },
102            ));
103        }
104    }
105
106    Err(tokens.error(ParseErrorType::ExpectedLiteral))
107}
108
109pub fn var(tokens: TokenList) -> ParseResult<VarExpression> {
110    identifier(tokens).map_val(|name| VarExpression { name })
111}
112
113pub fn root_var(tokens: TokenList) -> ParseResult<RootVarExpression> {
114    tokens
115        .terminal(TerminalToken::Namespace)
116        .determines(|tokens, root| {
117            identifier(tokens).map_val(|name| RootVarExpression { root, name })
118        })
119}
120
121pub fn table(tokens: TokenList) -> ParseResult<TableExpression> {
122    table_delimited(tokens, TerminalToken::OpenBrace, TerminalToken::CloseBrace)
123}
124
125pub fn table_delimited(
126    tokens: TokenList,
127    open_terminal: TerminalToken,
128    close_terminal: TerminalToken,
129) -> ParseResult<TableExpression> {
130    tokens.terminal(open_terminal).determines_and_opens(
131        ContextType::TableLiteral,
132        |tokens| tokens.terminal(close_terminal),
133        |tokens, open, close| {
134            let (tokens, slots) = tokens.many_until(
135                |tokens| tokens.is_ended() || tokens.terminal(TerminalToken::Ellipsis).is_ok(),
136                table_slot,
137            )?;
138            let (tokens, spread) = tokens.terminal(TerminalToken::Ellipsis).maybe(tokens)?;
139            Ok((
140                tokens,
141                TableExpression {
142                    open,
143                    slots,
144                    spread,
145                    close,
146                },
147            ))
148        },
149    )
150}
151
152pub fn class(tokens: TokenList) -> ParseResult<ClassExpression> {
153    tokens
154        .terminal(TerminalToken::Class)
155        .determines(|tokens, class| {
156            class_definition(tokens).map_val(|definition| ClassExpression { class, definition })
157        })
158        .with_context_from(ContextType::ClassLiteral, tokens)
159}
160
161pub fn array(tokens: TokenList) -> ParseResult<ArrayExpression> {
162    tokens
163        .terminal(TerminalToken::OpenSquare)
164        .determines_and_opens(
165            ContextType::ArrayLiteral,
166            |tokens| tokens.terminal(TerminalToken::CloseSquare),
167            |tokens, open, close| {
168                let (tokens, values) = tokens.many_until(
169                    |tokens| tokens.is_ended() || tokens.terminal(TerminalToken::Ellipsis).is_ok(),
170                    array_value,
171                )?;
172                let (tokens, spread) = tokens.terminal(TerminalToken::Ellipsis).maybe(tokens)?;
173                Ok((
174                    tokens,
175                    ArrayExpression {
176                        open,
177                        values,
178                        spread,
179                        close,
180                    },
181                ))
182            },
183        )
184}
185
186pub fn vector(tokens: TokenList) -> ParseResult<VectorExpression> {
187    tokens
188        .terminal(TerminalToken::Less)
189        .determines(|tokens, open| {
190            let (tokens, x) = expression(tokens, Precedence::Comma)?;
191            let (tokens, comma_1) = tokens.terminal(TerminalToken::Comma)?;
192            let (tokens, y) = expression(tokens, Precedence::Comma)?;
193            let (tokens, comma_2) = tokens.terminal(TerminalToken::Comma)?;
194            let (tokens, z) = expression(tokens, Precedence::Bitshift)?;
195            let (tokens, close) = tokens.terminal(TerminalToken::Greater)?;
196            Ok((
197                tokens,
198                VectorExpression {
199                    open,
200                    x,
201                    comma_1,
202                    y,
203                    comma_2,
204                    z,
205                    close,
206                },
207            ))
208        })
209        .with_context_from(ContextType::VectorLiteral, tokens)
210}
211
212pub fn prefix(tokens: TokenList) -> ParseResult<PrefixExpression> {
213    prefix_operator(tokens).determines(|tokens, operator| {
214        expression(tokens, Precedence::Prefix).map_val(|value| PrefixExpression { operator, value })
215    })
216}
217
218pub fn delegate(tokens: TokenList) -> ParseResult<DelegateExpression> {
219    tokens
220        .terminal(TerminalToken::Delegate)
221        .determines(|tokens, delegate| {
222            let (tokens, parent) = expression(tokens, Precedence::None)?;
223            let (tokens, colon) = tokens.terminal(TerminalToken::Colon)?;
224            let (tokens, value) = expression(tokens, Precedence::Comma)?;
225            Ok((
226                tokens,
227                DelegateExpression {
228                    delegate,
229                    parent,
230                    colon,
231                    value,
232                },
233            ))
234        })
235}
236
237pub fn expect(tokens: TokenList) -> ParseResult<ExpectExpression> {
238    tokens
239        .terminal(TerminalToken::Expect)
240        .determines(|tokens, expect| {
241            let (tokens, ty) = type_(tokens)?;
242            tokens.terminal(TerminalToken::OpenBracket).opens(
243                ContextType::Expression,
244                |tokens| tokens.terminal(TerminalToken::CloseBracket),
245                |tokens, open, close| {
246                    let (tokens, value) = expression(tokens, Precedence::None)?;
247                    Ok((
248                        tokens,
249                        ExpectExpression {
250                            expect,
251                            ty,
252                            open,
253                            value,
254                            close,
255                        },
256                    ))
257                },
258            )
259        })
260}
261
262struct ExpressionRef<'a, 's>(&'a mut Option<Box<Expression<'s>>>);
263impl<'a, 's> ExpressionRef<'a, 's> {
264    fn take(self) -> Box<Expression<'s>> {
265        self.0.take().unwrap()
266    }
267}
268
269fn operator<'s>(
270    tokens: TokenList<'s>,
271    precedence: Precedence,
272    left: ExpressionRef<'_, 's>,
273) -> ParseResult<'s, Box<Expression<'s>>> {
274    let left_ref = left.0;
275
276    property(tokens, precedence, ExpressionRef(left_ref))
277        .map_val(Expression::Property)
278        .or_try(|| {
279            ternary(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Ternary)
280        })
281        .or_try(|| binary(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Binary))
282        .or_try(|| index(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Index))
283        .or_try(|| {
284            postfix(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Postfix)
285        })
286        .or_try(|| call(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Call))
287        .or_try(|| comma(tokens, precedence, ExpressionRef(left_ref)).map_val(Expression::Comma))
288        .or_error(|| tokens.error(ParseErrorType::ExpectedOperator))
289        .map_val(Box::new)
290}
291
292fn property<'s>(
293    tokens: TokenList<'s>,
294    precedence: Precedence,
295    left: ExpressionRef<'_, 's>,
296) -> ParseResult<'s, PropertyExpression<'s>> {
297    // left associative
298    if precedence >= Precedence::Property {
299        return Err(tokens.error(ParseErrorType::Precedence));
300    }
301
302    tokens
303        .terminal(TerminalToken::Dot)
304        .determines(|tokens, dot| {
305            method_identifier(tokens).map_val(|property| PropertyExpression {
306                base: left.take(),
307                dot,
308                property,
309            })
310        })
311}
312
313fn ternary<'s>(
314    tokens: TokenList<'s>,
315    precedence: Precedence,
316    left: ExpressionRef<'_, 's>,
317) -> ParseResult<'s, TernaryExpression<'s>> {
318    // right associative
319    if precedence > Precedence::Ternary {
320        return Err(tokens.error(ParseErrorType::Precedence));
321    }
322
323    tokens
324        .terminal(TerminalToken::Question)
325        .determines(|tokens, question| {
326            let (tokens, true_value) = expression(tokens, Precedence::None)?;
327            let (tokens, separator) = tokens.terminal(TerminalToken::Colon)?;
328            let (tokens, false_value) = expression(tokens, Precedence::Ternary)?;
329
330            Ok((
331                tokens,
332                TernaryExpression {
333                    condition: left.take(),
334                    question,
335                    true_value,
336                    separator,
337                    false_value,
338                },
339            ))
340        })
341}
342
343fn binary<'s>(
344    tokens: TokenList<'s>,
345    precedence: Precedence,
346    left: ExpressionRef<'_, 's>,
347) -> ParseResult<'s, BinaryExpression<'s>> {
348    binary_operator(tokens)
349        .and_then(|(tokens, operator)| {
350            // left associative
351            if precedence >= operator.precedence() {
352                Err(tokens.error(ParseErrorType::Precedence))
353            } else {
354                Ok((tokens, operator))
355            }
356        })
357        .determines(|tokens, operator| {
358            expression(tokens, operator.precedence()).map_val(|right| BinaryExpression {
359                left: left.take(),
360                operator,
361                right,
362            })
363        })
364}
365
366fn index<'s>(
367    tokens: TokenList<'s>,
368    precedence: Precedence,
369    left: ExpressionRef<'_, 's>,
370) -> ParseResult<'s, IndexExpression<'s>> {
371    // left associative
372    if precedence >= Precedence::Postfix {
373        return Err(tokens.error(ParseErrorType::Precedence));
374    }
375
376    tokens
377        .terminal(TerminalToken::OpenSquare)
378        .determines_and_opens(
379            ContextType::Expression,
380            |tokens| tokens.terminal(TerminalToken::CloseSquare),
381            |tokens, open, close| {
382                expression(tokens, Precedence::None).map_val(|index| IndexExpression {
383                    base: left.take(),
384                    open,
385                    index,
386                    close,
387                })
388            },
389        )
390}
391
392fn postfix<'s>(
393    tokens: TokenList<'s>,
394    precedence: Precedence,
395    left: ExpressionRef<'_, 's>,
396) -> ParseResult<'s, PostfixExpression<'s>> {
397    // left associative
398    if precedence >= Precedence::Postfix {
399        return Err(tokens.error(ParseErrorType::Precedence));
400    }
401
402    // Newlines are not allowed before postfix operators to prevent this:
403    // ```
404    // a
405    // ++b
406    // ```
407    // from being parsed as:
408    // ```
409    // (a++) b
410    // ```
411    if tokens.is_newline() {
412        return Err(tokens.error(ParseErrorType::IllegalLineBreak));
413    }
414
415    postfix_operator(tokens)
416        .not_definite()
417        .map_val(|operator| PostfixExpression {
418            value: left.take(),
419            operator,
420        })
421}
422
423fn call<'s>(
424    tokens: TokenList<'s>,
425    precedence: Precedence,
426    left: ExpressionRef<'_, 's>,
427) -> ParseResult<'s, CallExpression<'s>> {
428    // left associative
429    if precedence >= Precedence::Postfix {
430        return Err(tokens.error(ParseErrorType::Precedence));
431    }
432
433    tokens
434        .terminal(TerminalToken::OpenBracket)
435        .determines_and_opens(
436            ContextType::CallArgumentList,
437            |tokens| tokens.terminal(TerminalToken::CloseBracket),
438            |tokens, open, close| {
439                tokens
440                    .separated_list_trailing0(
441                        |tokens| {
442                            let res = expression(tokens, Precedence::Comma).map_val(|expr| *expr);
443                            if tokens.is_ended() {
444                                res
445                            } else {
446                                res.definite()
447                            }
448                        },
449                        |tokens| tokens.terminal(TerminalToken::Comma),
450                    )
451                    .map_val(|args| (open, args, close))
452            },
453        )
454        .and_then(|(tokens, (open, arguments, close))| {
455            // Post-initializer may appear after a call, as long as it is on the same line.
456            let (tokens, post_initializer) = if tokens.is_newline() {
457                (tokens, None)
458            } else {
459                table(tokens).maybe(tokens)?
460            };
461
462            Ok((
463                tokens,
464                CallExpression {
465                    function: left.take(),
466                    open,
467                    arguments,
468                    close,
469                    post_initializer,
470                },
471            ))
472        })
473}
474
475fn comma<'s>(
476    tokens: TokenList<'s>,
477    precedence: Precedence,
478    left: ExpressionRef<'_, 's>,
479) -> ParseResult<'s, CommaExpression<'s>> {
480    // left associative
481    if precedence >= Precedence::Comma {
482        return Err(tokens.error(ParseErrorType::Precedence));
483    }
484
485    tokens
486        .terminal(TerminalToken::Comma)
487        .determines(|tokens, first_comma| {
488            let (tokens, mut values) = tokens.separated_list1(
489                |tokens| expression(tokens, Precedence::Comma).map_val(|expr| *expr),
490                |tokens| tokens.terminal(TerminalToken::Comma),
491            )?;
492            values.items.insert(0, (*left.take(), first_comma));
493            Ok((tokens, CommaExpression { values }))
494        })
495}