oxc/crates/oxc_parser/src/js/object.rs

259 lines
9.8 KiB
Rust

use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_diagnostics::Result;
use oxc_span::Span;
use oxc_syntax::operator::AssignmentOperator;
use super::list::ObjectExpressionProperties;
use crate::{diagnostics, lexer::Kind, list::SeparatedList, Parser};
impl<'a> Parser<'a> {
/// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer)
/// `ObjectLiteral`[Yield, Await] :
/// { }
/// { `PropertyDefinitionList`[?Yield, ?Await] }
/// { `PropertyDefinitionList`[?Yield, ?Await] , }
pub(crate) fn parse_object_expression(&mut self) -> Result<Expression<'a>> {
let span = self.start_span();
let has_in = self.ctx.has_in();
self.ctx = self.ctx.and_in(true);
let object_expression_properties = ObjectExpressionProperties::parse(self)?;
self.ctx = self.ctx.and_in(has_in);
Ok(self.ast.object_expression(
self.end_span(span),
object_expression_properties.elements,
object_expression_properties.trailing_comma,
))
}
/// `PropertyDefinition`[Yield, Await]
pub(crate) fn parse_property_definition(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
let peek_kind = self.peek_kind();
let class_element_name = peek_kind.is_class_element_name_start();
match self.cur_kind() {
// get ClassElementName
Kind::Get if class_element_name => self.parse_method_getter(),
// set ClassElementName
Kind::Set if class_element_name => self.parse_method_setter(),
// AsyncMethod
// AsyncGeneratorMethod
Kind::Async
if (class_element_name || peek_kind == Kind::Star)
&& !self.peek_token().is_on_new_line =>
{
self.parse_property_definition_method()
}
// GeneratorMethod
Kind::Star if class_element_name => self.parse_property_definition_method(),
// IdentifierReference
kind if kind.is_identifier_reference(false, false)
// test Kind::Dot to ignore ({ foo.bar: baz })
// see <https://stackoverflow.com/questions/30285947/syntaxerror-unexpected-token>
&& !matches!(
peek_kind,
Kind::LParen | Kind::Colon | Kind::LAngle | Kind::ShiftLeft | Kind::Dot
) =>
{
self.parse_property_definition_shorthand()
}
_ => {
let span = self.start_span();
let (key, computed) = self.parse_property_name()?;
if self.at(Kind::Colon) {
return self.parse_property_definition_assignment(span, key, computed);
}
if matches!(self.cur_kind(), Kind::LParen | Kind::LAngle | Kind::ShiftLeft) {
let method = self.parse_method(false, false)?;
return Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Init,
key,
self.ast.function_expression(method),
/* init */ None,
/* method */ true,
/* shorthand */ false,
/* computed */ computed,
));
}
Err(self.unexpected())
}
}
}
/// `PropertyDefinition`[Yield, Await] :
/// ... `AssignmentExpression`[+In, ?Yield, ?Await]
pub(crate) fn parse_spread_element(&mut self) -> Result<Box<'a, SpreadElement<'a>>> {
let span = self.start_span();
self.bump_any(); // advance `...`
let argument = self.parse_assignment_expression_base()?;
Ok(self.ast.spread_element(self.end_span(span), argument))
}
/// `PropertyDefinition`[Yield, Await] :
/// `IdentifierReference`[?Yield, ?Await]
/// `CoverInitializedName`[?Yield, ?Await]
fn parse_property_definition_shorthand(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
let span = self.start_span();
let identifier = self.parse_identifier_reference()?;
let key =
self.ast.alloc(IdentifierName { span: identifier.span, name: identifier.name.clone() });
// IdentifierReference ({ foo })
let value = Expression::Identifier(self.ast.alloc(identifier.clone()));
// CoverInitializedName ({ foo = bar })
let init = if self.eat(Kind::Eq) {
let right = self.parse_assignment_expression_base()?;
let left = AssignmentTarget::SimpleAssignmentTarget(
SimpleAssignmentTarget::AssignmentTargetIdentifier(self.ast.alloc(identifier)),
);
Some(self.ast.assignment_expression(
self.end_span(span),
AssignmentOperator::Assign,
left,
right,
))
} else {
None
};
Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Init,
PropertyKey::Identifier(key),
value,
init,
/* method */ false,
/* shorthand */ true,
/* computed */ false,
))
}
/// `PropertyDefinition`[Yield, Await] :
/// `PropertyName`[?Yield, ?Await] : `AssignmentExpression`[+In, ?Yield, ?Await]
fn parse_property_definition_assignment(
&mut self,
span: Span,
key: PropertyKey<'a>,
computed: bool,
) -> Result<Box<'a, ObjectProperty<'a>>> {
self.bump_any(); // bump `:`
let value = self.parse_assignment_expression_base()?;
Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Init,
key,
value,
None,
/* method */ false,
/* shorthand */ false,
/* computed */ computed,
))
}
/// `PropertyName`[Yield, Await] :
/// `LiteralPropertyName`
/// `ComputedPropertyName`[?Yield, ?Await]
pub(crate) fn parse_property_name(&mut self) -> Result<(PropertyKey<'a>, bool)> {
let mut computed = false;
let key = match self.cur_kind() {
Kind::Str => self.parse_literal_expression().map(PropertyKey::Expression)?,
kind if kind.is_number() => {
self.parse_literal_expression().map(PropertyKey::Expression)?
}
// { [foo]() {} }
Kind::LBrack => {
computed = true;
self.parse_computed_property_name().map(PropertyKey::Expression)?
}
_ => {
let ident = self.parse_identifier_name()?;
PropertyKey::Identifier(self.ast.alloc(ident))
}
};
Ok((key, computed))
}
/// `ComputedPropertyName`[Yield, Await] : [ `AssignmentExpression`[+In, ?Yield, ?Await] ]
pub(crate) fn parse_computed_property_name(&mut self) -> Result<Expression<'a>> {
self.bump_any(); // advance `[`
let has_in = self.ctx.has_in();
self.ctx = self.ctx.and_in(true);
let expression = self.parse_assignment_expression_base()?;
self.ctx = self.ctx.and_in(has_in);
self.expect(Kind::RBrack)?;
Ok(expression)
}
/// `PropertyDefinition`[Yield, Await] :
/// `MethodDefinition`[?Yield, ?Await]
fn parse_property_definition_method(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
let span = self.start_span();
let r#async = self.eat(Kind::Async);
let generator = self.eat(Kind::Star);
let (key, computed) = self.parse_property_name()?;
let method = self.parse_method(r#async, generator)?;
let value = self.ast.function_expression(method);
Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Init,
key,
value,
/* init */ None,
/* method */ true,
/* shorthand */ false,
/* computed */ computed,
))
}
/// `MethodDefinition`[Yield, Await] :
/// get `ClassElementName`[?Yield, ?Await] ( ) { `FunctionBody`[~Yield, ~Await] }
fn parse_method_getter(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
let span = self.start_span();
self.expect(Kind::Get)?;
let (key, computed) = self.parse_property_name()?;
let method = self.parse_method(false, false)?;
if method.params.parameters_count() != method.params.this_parameter().map_or(0, |_| 1) {
self.error(diagnostics::GetterParameters(method.params.span));
}
let value = self.ast.function_expression(method);
Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Get,
key,
value,
/* init */ None,
/* method */ false,
/* shorthand */ false,
/* computed */ computed,
))
}
/// `MethodDefinition`[Yield, Await] :
/// set `ClassElementName`[?Yield, ?Await] ( `PropertySetParameterList` ) { `FunctionBody`[~Yield, ~Await] }
fn parse_method_setter(&mut self) -> Result<Box<'a, ObjectProperty<'a>>> {
let span = self.start_span();
self.expect(Kind::Set)?;
let (key, computed) = self.parse_property_name()?;
let method = self.parse_method(false, false)?;
if method.params.parameters_count() != method.params.this_parameter().map_or(1, |_| 2) {
self.error(diagnostics::SetterParameters(method.params.span));
}
Ok(self.ast.object_property(
self.end_span(span),
PropertyKind::Set,
key,
self.ast.function_expression(method),
/* init */ None,
/* method */ false,
/* shorthand */ false,
/* computed */ computed,
))
}
}