use super::*;
#[parser]
impl<'a, I: Input> Parser<'a, I> {
pub(super) fn parse_object<T>(&mut self) -> PResult<'a, T>
where
Self: ParseObject<'a, T>,
{
let start = cur_pos!();
assert_and_bump!('{');
let mut props = vec![];
let mut first = true;
while !eat!('}') {
if first {
first = false;
} else {
expect!(',');
if eat!('}') {
break;
}
}
let prop = self.parse_object_prop()?;
props.push(prop);
}
Ok(Self::make_object(span!(start), props))
}
pub(super) fn parse_prop_name(&mut self) -> PResult<'a, PropName> {
let start = cur_pos!();
let v = match *cur!(true)? {
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => PropName::Str(Str {
span: span!(start),
value,
has_escape,
}),
_ => unreachable!(),
},
Num(_) => match bump!() {
Num(value) => PropName::Num(Number {
span: span!(start),
value,
}),
_ => unreachable!(),
},
Word(..) => match bump!() {
Word(w) => PropName::Ident(Ident {
span: span!(start),
sym: w.into(),
}),
_ => unreachable!(),
},
LBracket => {
bump!();
let expr = self
.include_in_expr(true)
.parse_assignment_expr()
.map(PropName::Computed)?;
expect!(']');
expr
}
_ => unexpected!(),
};
Ok(v)
}
}
#[parser]
impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
type Prop = PropOrSpread;
fn make_object(span: Span, props: Vec<Self::Prop>) -> Box<Expr> {
box Expr::Object(ObjectLit { span, props })
}
fn parse_object_prop(&mut self) -> PResult<'a, Self::Prop> {
let start = cur_pos!();
if eat!("...") {
let dot3_token = span!(start);
let expr = self.include_in_expr(true).parse_assignment_expr()?;
return Ok(PropOrSpread::Spread(SpreadElement { dot3_token, expr }));
}
if eat!('*') {
let span_of_gen = span!(start);
let name = self.parse_prop_name()?;
return self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, false, true)
.map(|function| {
PropOrSpread::Prop(box Prop::Method(MethodProp {
key: name,
function,
}))
});
}
let key = self.parse_prop_name()?;
if eat!(':') {
let value = self.include_in_expr(true).parse_assignment_expr()?;
return Ok(PropOrSpread::Prop(box Prop::KeyValue(KeyValueProp {
key,
value,
})));
}
if is!('(') {
return self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, false, false)
.map(|function| box Prop::Method(MethodProp { key, function }))
.map(PropOrSpread::Prop);
}
let ident = match key {
PropName::Ident(ident) => ident,
_ => unexpected!(),
};
if is_one_of!('=', ',', '}') {
let is_reserved_word = { self.ctx().is_reserved_word(&ident.sym) };
if is_reserved_word {
syntax_error!(ident.span, SyntaxError::ReservedWordInObjShorthandOrPat);
}
if eat!('=') {
let value = self.include_in_expr(true).parse_assignment_expr()?;
return Ok(PropOrSpread::Prop(box Prop::Assign(AssignProp {
key: ident,
value,
})));
}
return Ok(PropOrSpread::Prop(box Prop::from(ident)));
}
match ident.sym {
js_word!("get") | js_word!("set") | js_word!("async") => {
let key = self.parse_prop_name()?;
return match ident.sym {
js_word!("get") => self
.parse_fn_args_body(start, |_| Ok(vec![]), false, false)
.map(|Function { body, .. }| {
PropOrSpread::Prop(box Prop::Getter(GetterProp {
span: span!(start),
key,
body,
}))
}),
js_word!("set") => self
.parse_fn_args_body(
start,
|p| p.parse_formal_param().map(|pat| vec![pat]),
false,
false,
)
.map(|Function { params, body, .. }| {
debug_assert_eq!(params.len(), 1);
PropOrSpread::Prop(box Prop::Setter(SetterProp {
span: span!(start),
key,
body,
param: params.into_iter().next().unwrap(),
}))
}),
js_word!("async") => self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, true, false)
.map(|function| {
PropOrSpread::Prop(box Prop::Method(MethodProp { key, function }))
}),
_ => unreachable!(),
};
}
_ => unexpected!(),
}
}
}
#[parser]
impl<'a, I: Input> ParseObject<'a, Pat> for Parser<'a, I> {
type Prop = ObjectPatProp;
fn make_object(span: Span, props: Vec<Self::Prop>) -> Pat {
Pat::Object(ObjectPat { span, props })
}
fn parse_object_prop(&mut self) -> PResult<'a, Self::Prop> {
let start = cur_pos!();
let key = self.parse_prop_name()?;
if eat!(':') {
let value = box self.parse_binding_element()?;
return Ok(ObjectPatProp::KeyValue(KeyValuePatProp { key, value }));
}
let key = match key {
PropName::Ident(ident) => ident,
_ => unexpected!(),
};
let value = if eat!('=') {
self.include_in_expr(true)
.parse_assignment_expr()
.map(Some)?
} else {
if self.ctx().is_reserved_word(&key.sym) {
syntax_error!(key.span, SyntaxError::ReservedWordInObjShorthandOrPat);
}
None
};
Ok(ObjectPatProp::Assign(AssignPatProp {
span: span!(start),
key,
value,
}))
}
}