use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_syntax::operator::AssignmentOperator;
use crate::{
Context, ParserConfig as Config, ParserImpl, diagnostics,
lexer::Kind,
modifiers::{ModifierKind, ModifierKinds, Modifiers},
};
use super::FunctionKind;
impl<'a, C: Config> ParserImpl<'a, C> {
pub(crate) fn parse_object_expression(&mut self) -> Box<'a, ObjectExpression<'a>> {
let span = self.start_span();
let opening_span = self.cur_token().span();
self.expect(Kind::LCurly);
let (object_expression_properties, comma_span) = self.context_add(Context::In, |p| {
p.parse_delimited_list(
Kind::RCurly,
Kind::Comma,
opening_span,
Self::parse_object_expression_property,
)
});
if let Some(comma_span) = comma_span {
self.state.trailing_commas.insert(span, self.end_span(comma_span));
}
self.expect(Kind::RCurly);
self.ast.alloc_object_expression(self.end_span(span), object_expression_properties)
}
fn parse_object_expression_property(&mut self) -> ObjectPropertyKind<'a> {
match self.cur_kind() {
Kind::Dot3 => ObjectPropertyKind::SpreadProperty(self.parse_spread_element()),
_ => ObjectPropertyKind::ObjectProperty(self.parse_object_literal_element()),
}
}
fn parse_object_literal_element(&mut self) -> Box<'a, ObjectProperty<'a>> {
let span = self.start_span();
let modifiers = self.parse_modifiers(
false,
false,
);
if self.parse_contextual_modifier(Kind::Get) {
return self.parse_method_getter_setter(span, PropertyKind::Get, &modifiers);
}
if self.parse_contextual_modifier(Kind::Set) {
return self.parse_method_getter_setter(span, PropertyKind::Set, &modifiers);
}
let asterisk_token = self.eat(Kind::Star);
let token_is_identifier =
self.cur_kind().is_identifier_reference(self.ctx.has_yield(), self.ctx.has_await());
let (key, computed) = self.parse_property_name();
if asterisk_token || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
self.verify_modifiers(
&modifiers,
ModifierKinds::new([ModifierKind::Async]),
true,
diagnostics::modifier_cannot_be_used_here,
);
let method = self.parse_method(
modifiers.contains_async(),
asterisk_token,
FunctionKind::ObjectMethod,
);
return self.ast.alloc_object_property(
self.end_span(span),
PropertyKind::Init,
key,
Expression::FunctionExpression(method),
true,
false,
computed,
);
}
self.verify_modifiers(
&modifiers,
ModifierKinds::none(),
true,
diagnostics::modifier_cannot_be_used_here,
);
let is_shorthand_property_assignment = token_is_identifier && !self.at(Kind::Colon);
if is_shorthand_property_assignment {
if let PropertyKey::StaticIdentifier(identifier_name) = key {
let identifier_reference =
self.ast.identifier_reference(identifier_name.span, identifier_name.name);
let value = Expression::Identifier(self.alloc(identifier_reference.clone()));
if self.eat(Kind::Eq) {
let right = self.parse_assignment_expression_or_higher();
let left = AssignmentTarget::AssignmentTargetIdentifier(
self.alloc(identifier_reference),
);
let expr = self.ast.assignment_expression(
self.end_span(span),
AssignmentOperator::Assign,
left,
right,
);
self.state.cover_initialized_name.insert(span, expr);
}
self.ast.alloc_object_property(
self.end_span(span),
PropertyKind::Init,
PropertyKey::StaticIdentifier(identifier_name),
value,
false,
true,
computed,
)
} else {
self.unexpected()
}
} else {
self.parse_property_definition_assignment(span, key, computed)
}
}
pub(crate) fn parse_spread_element(&mut self) -> Box<'a, SpreadElement<'a>> {
let span = self.start_span();
self.bump_any(); let argument = self.parse_assignment_expression_or_higher();
self.ast.alloc_spread_element(self.end_span(span), argument)
}
fn parse_property_definition_assignment(
&mut self,
span: u32,
key: PropertyKey<'a>,
computed: bool,
) -> Box<'a, ObjectProperty<'a>> {
self.expect(Kind::Colon);
let value = self.parse_assignment_expression_or_higher();
self.ast.alloc_object_property(
self.end_span(span),
PropertyKind::Init,
key,
value,
false,
false,
computed,
)
}
pub(crate) fn parse_property_name(&mut self) -> (PropertyKey<'a>, bool) {
let mut computed = false;
let key = match self.cur_kind() {
Kind::Str => PropertyKey::from(self.parse_literal_expression()),
kind if kind.is_number() => PropertyKey::from(self.parse_literal_expression()),
Kind::LBrack => {
computed = true;
PropertyKey::from(self.parse_computed_property_name())
}
Kind::PrivateIdentifier => {
let private_ident = self.parse_private_identifier();
self.error(diagnostics::private_identifier_in_property_name(
&private_ident.name,
private_ident.span,
));
PropertyKey::PrivateIdentifier(self.alloc(private_ident))
}
_ => {
let ident = self.parse_identifier_name();
PropertyKey::StaticIdentifier(self.alloc(ident))
}
};
(key, computed)
}
pub(crate) fn parse_computed_property_name(&mut self) -> Expression<'a> {
self.bump_any();
let expression = self.context_add(Context::In, Self::parse_assignment_expression_or_higher);
self.expect(Kind::RBrack);
expression
}
fn parse_method_getter_setter(
&mut self,
span: u32,
kind: PropertyKind,
modifiers: &Modifiers,
) -> Box<'a, ObjectProperty<'a>> {
let (key, computed) = self.parse_property_name();
let function = self.parse_method(false, false, FunctionKind::ObjectMethod);
match kind {
PropertyKind::Get => self.check_getter(&function),
PropertyKind::Set => self.check_setter(&function),
PropertyKind::Init => {}
}
self.verify_modifiers(
modifiers,
ModifierKinds::none(),
true,
diagnostics::modifier_cannot_be_used_here,
);
self.ast.alloc_object_property(
self.end_span(span),
kind,
key,
Expression::FunctionExpression(function),
false,
false,
computed,
)
}
}