swc_ecma_lexer/common/parser/
ident.rs1use either::Either;
2use swc_atoms::atom;
3use swc_common::BytePos;
4use swc_ecma_ast::*;
5
6use super::{buffer::Buffer, expr::parse_str_lit, PResult, Parser};
7use crate::{
8 common::{context::Context, lexer::token::TokenFactory, parser::token_and_span::TokenAndSpan},
9 error::SyntaxError,
10};
11
12pub fn parse_module_export_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<ModuleExportName> {
14 let cur = p.input().cur();
15 let module_export_name = if cur.is_str() {
16 ModuleExportName::Str(parse_str_lit(p))
17 } else if cur.is_word() {
18 ModuleExportName::Ident(parse_ident_name(p)?.into())
19 } else {
20 unexpected!(p, "identifier or string");
21 };
22 Ok(module_export_name)
23}
24
25pub fn parse_ident_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<IdentName> {
28 let token_and_span = p.input().get_cur();
29 let start = token_and_span.span().lo;
30 let cur = token_and_span.token();
31 let w = if cur.is_word() {
32 p.input_mut().expect_word_token_and_bump()
33 } else if cur.is_jsx_name() && p.ctx().contains(Context::InType) {
34 p.input_mut().expect_jsx_name_token_and_bump()
35 } else {
36 syntax_error!(p, SyntaxError::ExpectedIdent)
37 };
38 Ok(IdentName::new(w, p.span(start)))
39}
40
41pub fn parse_maybe_private_name<'a, P: Parser<'a>>(
42 p: &mut P,
43) -> PResult<Either<PrivateName, IdentName>> {
44 let is_private = p.input().is(&P::Token::HASH);
45 if is_private {
46 parse_private_name(p).map(Either::Left)
47 } else {
48 parse_ident_name(p).map(Either::Right)
49 }
50}
51
52pub fn parse_private_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<PrivateName> {
53 let start = p.cur_pos();
54 p.assert_and_bump(&P::Token::HASH);
55 let hash_end = p.input().prev_span().hi;
56 if p.input().cur_pos() - hash_end != BytePos(0) {
57 syntax_error!(p, p.span(start), SyntaxError::SpaceBetweenHashAndIdent);
58 }
59 let id = parse_ident_name(p)?;
60 Ok(PrivateName {
61 span: p.span(start),
62 name: id.sym,
63 })
64}
65
66#[inline]
68pub fn parse_ident_ref<'a>(p: &mut impl Parser<'a>) -> PResult<Ident> {
69 let ctx = p.ctx();
70 parse_ident(
71 p,
72 !ctx.contains(Context::InGenerator),
73 !ctx.contains(Context::InAsync),
74 )
75}
76
77#[inline]
79pub fn parse_label_ident<'a>(p: &mut impl Parser<'a>) -> PResult<Ident> {
80 parse_ident_ref(p)
81}
82
83pub fn parse_binding_ident<'a>(
87 p: &mut impl Parser<'a>,
88 disallow_let: bool,
89) -> PResult<BindingIdent> {
90 trace_cur!(p, parse_binding_ident);
91
92 let cur = p.input().cur();
93 if disallow_let && cur.is_let() {
94 unexpected!(p, "let is reserved in const, let, class declaration")
95 } else if cur.is_unknown_ident() {
96 let span = p.input().cur_span();
97 let word = p.input_mut().expect_word_token_and_bump();
98 if atom!("arguments") == word || atom!("eval") == word {
99 p.emit_strict_mode_err(span, SyntaxError::EvalAndArgumentsInStrict);
100 }
101 return Ok(Ident::new_no_ctxt(word, span).into());
102 }
103
104 let ident = parse_ident(p, true, true)?;
106 let ctx = p.ctx();
107 if (ctx.intersects(Context::InAsync.union(Context::InStaticBlock)) && ident.sym == "await")
108 || (ctx.contains(Context::InGenerator) && ident.sym == "yield")
109 {
110 p.emit_err(ident.span, SyntaxError::ExpectedIdent);
111 }
112
113 Ok(ident.into())
114}
115
116pub fn parse_opt_binding_ident<'a>(
117 p: &mut impl Parser<'a>,
118 disallow_let: bool,
119) -> PResult<Option<BindingIdent>> {
120 trace_cur!(p, parse_opt_binding_ident);
121 let token_and_span = p.input().get_cur();
122 let cur = token_and_span.token();
123 if cur.is_this() && p.input().syntax().typescript() {
124 let start = token_and_span.span().lo;
125 Ok(Some(
126 Ident::new_no_ctxt(atom!("this"), p.span(start)).into(),
127 ))
128 } else if cur.is_word() && !cur.is_reserved(p.ctx()) {
129 parse_binding_ident(p, disallow_let).map(Some)
130 } else {
131 Ok(None)
132 }
133}
134
135pub fn parse_ident<'a>(
139 p: &mut impl Parser<'a>,
140 incl_yield: bool,
141 incl_await: bool,
142) -> PResult<Ident> {
143 trace_cur!(p, parse_ident);
144
145 let token_and_span = p.input().get_cur();
146 if !token_and_span.token().is_word() {
147 syntax_error!(p, SyntaxError::ExpectedIdent)
148 }
149 let span = token_and_span.span();
150 let start = span.lo;
151 let t = token_and_span.token();
152
153 if t.is_enum() {
158 let word = p.input_mut().expect_word_token_and_bump();
159 p.emit_err(span, SyntaxError::InvalidIdentInStrict(word.clone()));
160 return Ok(Ident::new_no_ctxt(word, p.span(start)));
161 } else if t.is_yield()
162 || t.is_let()
163 || t.is_static()
164 || t.is_implements()
165 || t.is_interface()
166 || t.is_package()
167 || t.is_private()
168 || t.is_protected()
169 || t.is_public()
170 {
171 let word = p.input_mut().expect_word_token_and_bump();
172 p.emit_strict_mode_err(span, SyntaxError::InvalidIdentInStrict(word.clone()));
173 return Ok(Ident::new_no_ctxt(word, p.span(start)));
174 };
175
176 let word;
177
178 if t.is_await() {
182 let ctx = p.ctx();
183 if ctx.contains(Context::InDeclare) {
184 word = atom!("await");
185 } else if ctx.contains(Context::InStaticBlock) {
186 syntax_error!(p, span, SyntaxError::ExpectedIdent)
187 } else if ctx.contains(Context::Module) | ctx.contains(Context::InAsync) {
188 syntax_error!(p, span, SyntaxError::InvalidIdentInAsync)
189 } else if incl_await {
190 word = atom!("await")
191 } else {
192 syntax_error!(p, span, SyntaxError::ExpectedIdent)
193 }
194 } else if t.is_this() && p.input().syntax().typescript() {
195 word = atom!("this")
196 } else if t.is_let() {
197 word = atom!("let")
198 } else if t.is_known_ident() {
199 let ident = t.take_known_ident();
200 word = ident
201 } else if t.is_unknown_ident() {
202 let word = p.input_mut().expect_word_token_and_bump();
203 if p.ctx().contains(Context::InClassField) && word == atom!("arguments") {
204 p.emit_err(span, SyntaxError::ArgumentsInClassField)
205 }
206 return Ok(Ident::new_no_ctxt(word, p.span(start)));
207 } else if t.is_yield() && incl_yield {
208 word = atom!("yield")
209 } else if t.is_null() || t.is_true() || t.is_false() || t.is_keyword() {
210 syntax_error!(p, span, SyntaxError::ExpectedIdent)
211 } else {
212 unreachable!()
213 }
214 p.bump();
215
216 Ok(Ident::new_no_ctxt(word, p.span(start)))
217}