swc_ecma_parser/parser/
expr.rs1use either::Either;
2use swc_common::{BytePos, Span, Spanned};
3use swc_ecma_lexer::{
4 common::parser::{
5 class_and_fn::parse_fn_expr,
6 expr::{
7 parse_array_lit, parse_await_expr, parse_lit, parse_member_expr_or_new_expr,
8 parse_paren_expr_or_arrow_fn, parse_primary_expr_rest, parse_this_expr,
9 try_parse_async_start, try_parse_regexp,
10 },
11 object::parse_object_expr,
12 token_and_span::TokenAndSpan,
13 typescript::parse_ts_type_assertion,
14 },
15 error::SyntaxError,
16};
17
18use super::*;
19
20mod ops;
21#[cfg(test)]
22mod tests;
23
24use crate::parser::Parser;
25
26impl<I: Tokens> Parser<I> {
27 pub fn parse_expr(&mut self) -> PResult<Box<Expr>> {
28 ParserTrait::parse_expr(self)
29 }
30
31 #[allow(dead_code)]
32 fn parse_member_expr(&mut self) -> PResult<Box<Expr>> {
33 parse_member_expr_or_new_expr(self, false)
34 }
35
36 pub(super) fn parse_unary_expr(&mut self) -> PResult<Box<Expr>> {
37 trace_cur!(self, parse_unary_expr);
38
39 let token_and_span = self.input().get_cur();
40 let start = token_and_span.span().lo;
41 let cur = *token_and_span.token();
42
43 if cur == Token::Lt && self.input().syntax().typescript() && !self.input().syntax().jsx() {
44 self.bump(); return if self.input_mut().eat(&Token::Const) {
46 self.expect(&Token::Gt)?;
47 let expr = self.parse_unary_expr()?;
48 Ok(TsConstAssertion {
49 span: self.span(start),
50 expr,
51 }
52 .into())
53 } else {
54 parse_ts_type_assertion(self, start)
55 .map(Expr::from)
56 .map(Box::new)
57 };
58 } else if cur == Token::Lt
59 && self.input().syntax().jsx()
60 && self.input_mut().peek().is_some_and(|peek| {
61 (*peek).is_word() || peek == &Token::Gt || peek.should_rescan_into_gt_in_jsx()
62 })
63 {
64 fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
65 match e {
66 Either::Left(l) => l.into(),
67 Either::Right(r) => r.into(),
68 }
69 }
70 return self.parse_jsx_element(true).map(into_expr);
71 } else if matches!(cur, Token::PlusPlus | Token::MinusMinus) {
72 let op = if cur == Token::PlusPlus {
74 op!("++")
75 } else {
76 op!("--")
77 };
78 self.bump();
79
80 let arg = self.parse_unary_expr()?;
81 let span = Span::new_with_checked(start, arg.span_hi());
82 self.check_assign_target(&arg, false);
83
84 return Ok(UpdateExpr {
85 span,
86 prefix: true,
87 op,
88 arg,
89 }
90 .into());
91 } else if cur == Token::Delete
92 || cur == Token::Void
93 || cur == Token::TypeOf
94 || cur == Token::Plus
95 || cur == Token::Minus
96 || cur == Token::Tilde
97 || cur == Token::Bang
98 {
99 let op = if cur == Token::Delete {
101 op!("delete")
102 } else if cur == Token::Void {
103 op!("void")
104 } else if cur == Token::TypeOf {
105 op!("typeof")
106 } else if cur == Token::Plus {
107 op!(unary, "+")
108 } else if cur == Token::Minus {
109 op!(unary, "-")
110 } else if cur == Token::Tilde {
111 op!("~")
112 } else {
113 debug_assert!(cur == Token::Bang);
114 op!("!")
115 };
116 self.bump();
117 let arg_start = self.cur_pos() - BytePos(1);
118 let arg = match self.parse_unary_expr() {
119 Ok(expr) => expr,
120 Err(err) => {
121 self.emit_error(err);
122 Invalid {
123 span: Span::new_with_checked(arg_start, arg_start),
124 }
125 .into()
126 }
127 };
128
129 if op == op!("delete") {
130 if let Expr::Ident(ref i) = *arg {
131 self.emit_strict_mode_err(i.span, SyntaxError::TS1102)
132 }
133 }
134
135 return Ok(UnaryExpr {
136 span: Span::new_with_checked(start, arg.span_hi()),
137 op,
138 arg,
139 }
140 .into());
141 } else if cur == Token::Await {
142 return parse_await_expr(self, None);
143 }
144
145 let expr = self.parse_lhs_expr()?;
147 if let Expr::Arrow { .. } = *expr {
148 return Ok(expr);
149 }
150
151 if self.input_mut().had_line_break_before_cur() {
153 return Ok(expr);
154 }
155
156 let cur = self.input().cur();
157 if cur == &Token::PlusPlus || cur == &Token::MinusMinus {
158 let op = if cur == &Token::PlusPlus {
159 op!("++")
160 } else {
161 op!("--")
162 };
163
164 self.check_assign_target(&expr, false);
165 self.bump();
166
167 return Ok(UpdateExpr {
168 span: self.span(expr.span_lo()),
169 prefix: false,
170 op,
171 arg: expr,
172 }
173 .into());
174 }
175 Ok(expr)
176 }
177
178 pub(super) fn parse_primary_expr(&mut self) -> PResult<Box<Expr>> {
179 trace_cur!(self, parse_primary_expr);
180 let start = self.input().cur_pos();
181 let can_be_arrow = self
182 .state
183 .potential_arrow_start
184 .map(|s| s == start)
185 .unwrap_or(false);
186 let tok = self.input.cur();
187 match *tok {
188 Token::This => return parse_this_expr(self, start),
189 Token::Async => {
190 if let Some(res) = try_parse_async_start(self, can_be_arrow) {
191 return res;
192 }
193 }
194 Token::LBracket => {
195 return self.do_outside_of_context(Context::WillExpectColonForCond, parse_array_lit)
196 }
197 Token::LBrace => {
198 return parse_object_expr(self).map(Box::new);
199 }
200 Token::Function => {
202 return parse_fn_expr(self);
203 }
204 Token::Null | Token::True | Token::False | Token::Num | Token::BigInt | Token::Str => {
206 return parse_lit(self).map(|lit| lit.into());
207 }
208 Token::Slash | Token::DivEq => {
210 if let Some(res) = try_parse_regexp(self, start) {
211 return Ok(res);
212 }
213 }
214 Token::LParen => return parse_paren_expr_or_arrow_fn(self, can_be_arrow, None),
215 Token::NoSubstitutionTemplateLiteral => {
216 return Ok(self.parse_no_substitution_template_literal(false)?.into())
217 }
218 Token::TemplateHead => {
219 return Ok(self
221 .do_outside_of_context(Context::WillExpectColonForCond, |p| p.parse_tpl(false))?
222 .into());
223 }
224 _ => {}
225 }
226
227 parse_primary_expr_rest(self, start, can_be_arrow)
228 }
229}