boa/syntax/parser/expression/
update.rs

1//! Update expression parsing.
2//!
3//! More information:
4//!  - [ECMAScript specification][spec]
5//!
6//! [spec]: https://tc39.es/ecma262/#sec-update-expressions
7
8use super::left_hand_side::LeftHandSideExpression;
9use crate::{
10    profiler::BoaProfiler,
11    syntax::{
12        ast::{node, op::UnaryOp, Node, Punctuator},
13        lexer::TokenKind,
14        parser::{
15            expression::unary::UnaryExpression, AllowAwait, AllowYield, Cursor, ParseError,
16            ParseResult, TokenParser,
17        },
18    },
19};
20
21use std::io::Read;
22
23/// Parses an update expression.
24///
25/// More information:
26///  - [ECMAScript specification][spec]
27///
28/// [spec]: https://tc39.es/ecma262/#prod-UpdateExpression
29#[derive(Debug, Clone, Copy)]
30pub(super) struct UpdateExpression {
31    allow_yield: AllowYield,
32    allow_await: AllowAwait,
33}
34
35impl UpdateExpression {
36    /// Creates a new `UpdateExpression` parser.
37    pub(super) fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
38    where
39        Y: Into<AllowYield>,
40        A: Into<AllowAwait>,
41    {
42        Self {
43            allow_yield: allow_yield.into(),
44            allow_await: allow_await.into(),
45        }
46    }
47}
48
49impl<R> TokenParser<R> for UpdateExpression
50where
51    R: Read,
52{
53    type Output = Node;
54
55    fn parse(self, cursor: &mut Cursor<R>) -> ParseResult {
56        let _timer = BoaProfiler::global().start_event("UpdateExpression", "Parsing");
57
58        let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?;
59        match tok.kind() {
60            TokenKind::Punctuator(Punctuator::Inc) => {
61                cursor.next()?.expect("Punctuator::Inc token disappeared");
62                return Ok(node::UnaryOp::new(
63                    UnaryOp::IncrementPre,
64                    UnaryExpression::new(self.allow_yield, self.allow_await).parse(cursor)?,
65                )
66                .into());
67            }
68            TokenKind::Punctuator(Punctuator::Dec) => {
69                cursor.next()?.expect("Punctuator::Dec token disappeared");
70                return Ok(node::UnaryOp::new(
71                    UnaryOp::DecrementPre,
72                    UnaryExpression::new(self.allow_yield, self.allow_await).parse(cursor)?,
73                )
74                .into());
75            }
76            _ => {}
77        }
78
79        let lhs = LeftHandSideExpression::new(self.allow_yield, self.allow_await).parse(cursor)?;
80        if let Some(tok) = cursor.peek(0)? {
81            match tok.kind() {
82                TokenKind::Punctuator(Punctuator::Inc) => {
83                    cursor.next()?.expect("Punctuator::Inc token disappeared");
84                    return Ok(node::UnaryOp::new(UnaryOp::IncrementPost, lhs).into());
85                }
86                TokenKind::Punctuator(Punctuator::Dec) => {
87                    cursor.next()?.expect("Punctuator::Dec token disappeared");
88                    return Ok(node::UnaryOp::new(UnaryOp::DecrementPost, lhs).into());
89                }
90                _ => {}
91            }
92        }
93
94        Ok(lhs)
95    }
96}