use super::{pat::PatType, util::ExprExt, *};
use crate::{lexer::TokenContext, token::AssignOpToken};
use either::Either;
use swc_common::{ast_node, Spanned};
mod ops;
#[cfg(test)]
mod tests;
mod verifier;
#[parser]
impl<'a, I: Input> Parser<'a, I> {
pub fn parse_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let expr = self.parse_assignment_expr()?;
let start = expr.span().lo();
if is!(',') {
let mut exprs = vec![expr];
while eat!(',') {
exprs.push(self.parse_assignment_expr()?);
}
let end = exprs.last().unwrap().span().hi();
return Ok(Box::new(Expr::Seq(SeqExpr {
span: span!(start),
exprs,
})));
}
Ok(expr)
}
pub(super) fn parse_assignment_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
if self.input.syntax().typescript() {
if is!(JSXTagStart) {
let cur_context = self.input.token_context().current();
assert_eq!(cur_context, Some(TokenContext::JSXOpeningTag));
assert_eq!(
self.input.token_context().0[self.input.token_context().len() - 2],
TokenContext::JSXExpr
);
let res = self.try_parse_ts(|p| p.parse_assignment_expr_base().map(Some));
if let Some(res) = res {
return Ok(res);
} else {
assert_eq!(
self.input.token_context().current(),
Some(TokenContext::JSXOpeningTag)
);
self.input.token_context_mut().pop();
assert_eq!(
self.input.token_context().current(),
Some(TokenContext::JSXExpr)
);
self.input.token_context_mut().pop();
}
}
}
let res = self.try_parse_ts(|p| {
let type_parameters = p.parse_ts_type_params()?;
let mut arrow = p.parse_assignment_expr_base()?;
match *arrow {
Expr::Arrow(ArrowExpr {
ref mut type_params,
..
}) => {
*type_params = Some(type_parameters);
}
_ => unexpected!(),
}
Ok(Some(arrow))
});
if let Some(res) = res {
return Ok(res);
}
self.parse_assignment_expr_base()
}
fn parse_assignment_expr_base(&mut self) -> PResult<'a, (Box<Expr>)> {
if self.ctx().in_generator && is!("yield") {
return self.parse_yield_expr();
}
self.state.potential_arrow_start = match *cur!(true)? {
Word(Word::Ident(..)) | tok!('(') | tok!("yield") => Some(cur_pos!()),
_ => None,
};
let start = cur_pos!();
let cond = self.parse_cond_expr()?;
return_if_arrow!(cond);
match *cond {
Expr::Cond(..) | Expr::Bin(..) | Expr::Unary(..) | Expr::Update(..) => return Ok(cond),
_ => {}
}
match cur!(false) {
Ok(&Token::AssignOp(op)) => {
let left = if op == AssignOpToken::Assign {
self.reparse_expr_as_pat(PatType::AssignPat, cond)
.map(Box::new)
.map(PatOrExpr::Pat)?
} else {
if !cond.is_valid_simple_assignment_target(self.ctx().strict) {
syntax_error!(cond.span(), SyntaxError::NotSimpleAssign)
}
PatOrExpr::Expr(cond)
};
bump!();
let right = self.parse_assignment_expr()?;
Ok(Box::new(Expr::Assign(AssignExpr {
span: span!(start),
op,
left,
right,
})))
}
_ => Ok(cond),
}
}
fn parse_cond_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
let test = self.parse_bin_expr()?;
return_if_arrow!(test);
if eat!('?') {
let cons = self.include_in_expr(true).parse_assignment_expr()?;
expect!(':');
let alt = self.parse_assignment_expr()?;
Ok(Box::new(Expr::Cond(CondExpr {
test,
cons,
alt,
span: span!(start),
})))
} else {
return Ok(test);
}
}
fn parse_primary_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let _ = cur!(false);
let start = cur_pos!();
let can_be_arrow = self
.state
.potential_arrow_start
.map(|s| s == start)
.unwrap_or(false);
if eat!("this") {
return Ok(Box::new(Expr::This(ThisExpr { span: span!(start) })));
}
if is!("async") {
if peeked_is!("function") && !self.input.has_linebreak_between_cur_and_peeked() {
return self.parse_async_fn_expr();
}
if can_be_arrow && self.input.syntax().typescript() && peeked_is!('<') {
if let Some(res) = self.try_parse_ts(|p| {
let start = cur_pos!();
assert_and_bump!("async");
p.try_parse_ts_generic_async_arrow_fn(start)
}) {
return Ok(Box::new(Expr::Arrow(res)));
}
}
if can_be_arrow && peeked_is!('(') {
expect!("async");
let async_span = self.input.prev_span();
return self.parse_paren_expr_or_arrow_fn(can_be_arrow, Some(async_span));
}
}
if is!('[') {
return self.parse_array_lit();
}
if is!('{') {
return self.parse_object();
}
if is!("function") {
return self.parse_fn_expr();
}
if is!("class") {
return self.parse_class_expr();
}
if {
match *cur!(false)? {
tok!("null")
| tok!("true")
| tok!("false")
| Token::Num(..)
| Token::Str { .. } => true,
_ => false,
}
} {
return Ok(Box::new(Expr::Lit(self.parse_lit()?)));
}
if {
match *cur!(false)? {
Token::Regex(..) => true,
_ => false,
}
} {
match bump!() {
Token::Regex(exp, flags) => {
return Ok(Box::new(Expr::Lit(Lit::Regex(Regex {
span: span!(start),
exp,
flags,
}))));
}
_ => unreachable!(),
}
}
if is!('`') {
return Ok(Box::new(Expr::Tpl(self.parse_tpl()?)));
}
if is!('(') {
return self.parse_paren_expr_or_arrow_fn(can_be_arrow, None);
}
if is!("let") || (self.input.syntax().typescript() && is!(IdentName)) || is!(IdentRef) {
let id = self.parse_ident_name()?;
if can_be_arrow && id.sym == js_word!("async") && is!(BindingIdent) {
let arg = self.parse_binding_ident().map(Pat::from)?;
let params = vec![arg];
expect!("=>");
let body = self.parse_fn_body(true, false)?;
return Ok(Box::new(Expr::Arrow(ArrowExpr {
span: span!(start),
body,
params,
is_async: true,
is_generator: false,
return_type: None,
type_params: None,
})));
} else if can_be_arrow && !self.input.had_line_break_before_cur() && eat!("=>") {
let params = vec![id.into()];
let body = self.parse_fn_body(false, false)?;
return Ok(Box::new(Expr::Arrow(ArrowExpr {
span: span!(start),
body,
params,
is_async: false,
is_generator: false,
return_type: None,
type_params: None,
})));
} else {
return Ok(Box::new(Expr::Ident(id)));
}
}
unexpected!()
}
fn parse_array_lit(&mut self) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
assert_and_bump!('[');
let mut elems = vec![];
while !eof!() && !is!(']') {
if is!(',') {
expect!(',');
elems.push(None);
continue;
}
elems.push(
self.include_in_expr(true)
.parse_expr_or_spread()
.map(Some)?,
);
if is!(',') {
expect!(',');
}
}
expect!(']');
let span = span!(start);
Ok(Box::new(Expr::Array(ArrayLit { span, elems })))
}
fn parse_member_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
self.parse_member_expr_or_new_expr(false)
}
fn parse_member_expr_or_new_expr(&mut self, is_new_expr: bool) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
if eat!("new") {
let span_of_new = span!(start);
if eat!('.') {
let start_of_target = cur_pos!();
if eat!("target") {
return Ok(Box::new(Expr::MetaProp(MetaPropExpr {
meta: Ident::new(js_word!("new"), span_of_new),
prop: Ident::new(js_word!("target"), span!(start_of_target)),
})));
}
unexpected!()
}
let callee = self.parse_member_expr_or_new_expr(is_new_expr)?;
return_if_arrow!(callee);
let type_args = if self.input.syntax().typescript() && is!('<') {
self.try_parse_ts(|p| {
let args = p.parse_ts_type_args()?;
if !is!('(') {
unexpected!()
}
Ok(Some(args))
})
} else {
None
};
if !is_new_expr || is!('(') {
let args = self.parse_args().map(Some)?;
let new_expr = ExprOrSuper::Expr(Box::new(Expr::New(NewExpr {
span: span!(start),
callee,
args,
type_args,
})));
return self.parse_subscripts(new_expr, true);
}
return Ok(Box::new(Expr::New(NewExpr {
span: span!(start),
callee,
args: None,
type_args,
})));
}
if eat!("super") {
let base = ExprOrSuper::Super(span!(start));
return self.parse_subscripts(base, true);
}
let obj = self.parse_primary_expr()?;
return_if_arrow!(obj);
self.parse_subscripts(ExprOrSuper::Expr(obj), true)
}
pub(super) fn parse_new_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
self.parse_member_expr_or_new_expr(true)
}
pub(super) fn parse_args(&mut self) -> PResult<'a, (Vec<ExprOrSpread>)> {
expect!('(');
let mut first = true;
let mut expr_or_spreads = vec![];
while !eof!() && !is!(')') {
if first {
first = false;
} else {
expect!(',');
if is!(')') {
break;
}
}
expr_or_spreads.push(self.include_in_expr(true).parse_expr_or_spread()?);
}
expect!(')');
Ok(expr_or_spreads)
}
pub(super) fn parse_expr_or_spread(&mut self) -> PResult<'a, ExprOrSpread> {
let start = cur_pos!();
if eat!("...") {
let spread = Some(span!(start));
self.include_in_expr(true)
.parse_assignment_expr()
.map(|expr| ExprOrSpread { spread, expr })
} else {
self.parse_assignment_expr()
.map(|expr| ExprOrSpread { spread: None, expr })
}
}
fn parse_paren_expr_or_arrow_fn(
&mut self,
can_be_arrow: bool,
async_span: Option<Span>,
) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
let paren_items = self.include_in_expr(true).parse_args_or_pats()?;
let has_pattern = paren_items.iter().any(|item| match item {
PatOrExprOrSpread::Pat(..) => true,
_ => false,
});
let return_type = if self.input.syntax().typescript() && is!(':') {
let start = cur_pos!();
Some(self.parse_ts_type_or_type_predicate_ann(&tok!(':'))?)
} else {
None
};
if has_pattern || return_type.is_some() || is!("=>") {
if self.input.had_line_break_before_cur() {
syntax_error!(span!(start), SyntaxError::LineBreakBeforeArrow);
}
if !can_be_arrow {
unexpected!()
}
expect!("=>");
let params = self
.parse_paren_items_as_params(paren_items)?
.into_iter()
.collect();
let body: BlockStmtOrExpr = self.parse_fn_body(async_span.is_some(), false)?;
return Ok(Box::new(Expr::Arrow(ArrowExpr {
span: span!(start),
is_async: async_span.is_some(),
is_generator: false,
params,
body,
return_type,
type_params: None,
})));
}
let expr_or_spreads = paren_items
.into_iter()
.map(|item| -> PResult<'a, _> {
match item {
PatOrExprOrSpread::ExprOrSpread(e) => Ok(e),
_ => syntax_error!(item.span(), SyntaxError::InvalidExpr),
}
})
.collect::<Result<Vec<_>, _>>()?;
if let Some(async_span) = async_span {
return Ok(Box::new(Expr::Call(CallExpr {
span: span!(async_span.lo()),
callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new(
"async".into(),
async_span,
)))),
args: expr_or_spreads,
type_args: None,
})));
}
if expr_or_spreads.len() == 0 {
syntax_error!(
Span::new(start, last_pos!(), Default::default()),
SyntaxError::EmptyParenExpr
);
}
if expr_or_spreads.len() == 1 {
let expr = match expr_or_spreads.into_iter().next().unwrap() {
ExprOrSpread {
spread: Some(..),
ref expr,
} => syntax_error!(expr.span(), SyntaxError::SpreadInParenExpr),
ExprOrSpread { expr, .. } => expr,
};
return Ok(Box::new(Expr::Paren(ParenExpr {
span: span!(start),
expr,
})));
} else {
debug_assert!(expr_or_spreads.len() >= 2);
let mut exprs = Vec::with_capacity(expr_or_spreads.len());
for expr in expr_or_spreads {
match expr {
ExprOrSpread {
spread: Some(..),
ref expr,
} => syntax_error!(expr.span(), SyntaxError::SpreadInParenExpr),
ExprOrSpread { expr, .. } => exprs.push(expr),
}
}
debug_assert!(exprs.len() >= 2);
let seq_expr = Box::new(Expr::Seq(SeqExpr {
span: Span::new(
exprs.first().unwrap().span().lo(),
exprs.last().unwrap().span().hi(),
Default::default(),
),
exprs,
}));
return Ok(Box::new(Expr::Paren(ParenExpr {
span: span!(start),
expr: seq_expr,
})));
}
}
fn parse_tpl_elements(
&mut self,
is_tagged: bool,
) -> PResult<'a, (Vec<Box<Expr>>, Vec<TplElement>)> {
let mut exprs = vec![];
let cur_elem = self.parse_tpl_element(is_tagged)?;
let mut is_tail = cur_elem.tail;
let mut quasis = vec![cur_elem];
while !is_tail {
expect!("${");
exprs.push(self.include_in_expr(true).parse_expr()?);
expect!('}');
let elem = self.parse_tpl_element(is_tagged)?;
is_tail = elem.tail;
quasis.push(elem);
}
Ok((exprs, quasis))
}
fn parse_tagged_tpl(
&mut self,
tag: Box<Expr>,
type_params: Option<TsTypeParamInstantiation>,
) -> PResult<'a, TaggedTpl> {
let start = cur_pos!();
assert_and_bump!('`');
let (exprs, quasis) = self.parse_tpl_elements(false)?;
expect!('`');
let span = span!(start);
Ok(TaggedTpl {
span,
tag,
exprs,
type_params,
quasis,
})
}
fn parse_tpl(&mut self) -> PResult<'a, Tpl> {
let start = cur_pos!();
assert_and_bump!('`');
let (exprs, quasis) = self.parse_tpl_elements(false)?;
expect!('`');
let span = span!(start);
Ok(Tpl {
span,
exprs,
quasis,
})
}
fn parse_tpl_element(&mut self, is_tagged: bool) -> PResult<'a, TplElement> {
let start = cur_pos!();
let (raw, cooked) = match *cur!(true)? {
Token::Template { .. } => match bump!() {
Token::Template {
raw,
cooked,
has_escape,
} => (
Str {
span: span!(start),
value: raw,
has_escape,
},
Some(Str {
span: span!(start),
value: cooked,
has_escape,
}),
),
_ => unreachable!(),
},
_ => unexpected!(),
};
let tail = is!('`');
Ok(TplElement {
span: span!(start),
raw,
tail,
cooked,
})
}
fn parse_subscripts(
&mut self,
mut obj: ExprOrSuper,
no_call: bool,
) -> PResult<'a, (Box<Expr>)> {
loop {
obj = match self.parse_subscript(obj, no_call)? {
(expr, false) => return Ok(expr),
(expr, true) => ExprOrSuper::Expr(expr),
}
}
}
fn parse_subscript(
&mut self,
obj: ExprOrSuper,
no_call: bool,
) -> PResult<'a, (Box<Expr>, bool)> {
let _ = cur!(false);
let start = cur_pos!();
if self.input.syntax().typescript() {
if !self.input.had_line_break_before_cur() && is!('!') {
self.input.set_expr_allowed(false);
assert_and_bump!('!');
let expr = match obj {
ExprOrSuper::Super(..) => unimplemented!("super!"),
ExprOrSuper::Expr(expr) => expr,
};
return Ok((
Box::new(Expr::TsNonNull(TsNonNullExpr {
span: span!(start),
expr,
})),
true,
));
}
let obj = obj.clone();
if {
match obj {
ExprOrSuper::Expr(..) => true,
_ => false,
}
} && is!('<')
{
let result = self.try_parse_ts(|p| {
if !no_call
&& p.at_possible_async(match obj {
ExprOrSuper::Expr(ref expr) => &*expr,
_ => unreachable!(),
})?
{
let async_arrow_fn = p.try_parse_ts_generic_async_arrow_fn(start)?;
if let Some(async_arrow_fn) = async_arrow_fn {
return Ok(Some((Box::new(Expr::Arrow(async_arrow_fn)), true)));
}
}
let type_args = p.parse_ts_type_args()?;
if !no_call && is!('(') {
let args = p.parse_args()?;
return Ok(Some((
Box::new(Expr::Call(CallExpr {
span: span!(start),
callee: obj,
type_args: Some(type_args),
args,
})),
true,
)));
} else if is!('`') {
return p
.parse_tagged_tpl(
match obj {
ExprOrSuper::Expr(obj) => obj,
_ => unreachable!(),
},
Some(type_args),
)
.map(|expr| (Box::new(Expr::TaggedTpl(expr)), true))
.map(Some);
} else {
unexpected!()
}
});
if let Some(result) = result {
return Ok(result);
}
}
}
if eat!('.') {
let prop: Box<Expr> = Box::new(self.parse_ident_name().map(Expr::from)?);
return Ok((
Box::new(Expr::Member(MemberExpr {
span: span!(start),
obj,
prop,
computed: false,
})),
true,
));
}
if eat!('[') {
let prop = self.include_in_expr(true).parse_expr()?;
expect!(']');
return Ok((
Box::new(Expr::Member(MemberExpr {
span: span!(start),
obj,
prop,
computed: true,
})),
true,
));
}
if !no_call && is!('(') {
let args = self.parse_args()?;
return Ok((
Box::new(Expr::Call(CallExpr {
span: span!(start),
callee: obj,
args,
type_args: None,
})),
true,
));
}
match obj {
ExprOrSuper::Expr(expr) => {
if is!('`') {
let tpl = self.parse_tagged_tpl(expr, None)?;
return Ok((Box::new(Expr::TaggedTpl(tpl)), true));
}
Ok((expr, false))
}
ExprOrSuper::Super(..) => {
if no_call {
unexpected!()
}
unexpected!()
}
}
}
pub(super) fn parse_lhs_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
if self.input.syntax().jsx() {
fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
match e {
Either::Left(l) => Box::new(l.into()),
Either::Right(r) => Box::new(r.into()),
}
}
match *cur!(true)? {
Token::JSXText { .. } => {
return self
.parse_jsx_text()
.map(Lit::JSXText)
.map(Expr::Lit)
.map(Box::new);
}
Token::JSXTagStart => {
return self.parse_jsx_element().map(into_expr);
}
_ => {}
}
if is!('<') && !peeked_is!('!') {
return self.parse_jsx_element().map(into_expr);
}
}
if eat!("super") {
let obj = ExprOrSuper::Super(span!(start));
return self.parse_subscripts(obj, false);
}
let callee = self.parse_new_expr()?;
return_if_arrow!(callee);
let type_args = if self.input.syntax().typescript() && is!('<') {
self.try_parse_ts(|p| {
let type_args = p.parse_ts_type_args()?;
if is!('(') {
Ok(Some(type_args))
} else {
Ok(None)
}
})
} else {
None
};
match *callee {
Expr::New(ne @ NewExpr { args: None, .. }) => {
if type_args.is_some() {
expect!('(');
}
assert_ne!(
cur!(false).ok(),
Some(&tok!('(')),
"parse_new_expr() should eat paren if it exists"
);
return Ok(Box::new(Expr::New(NewExpr { type_args, ..ne })));
}
_ => {}
}
if is!('(') {
let args = self.parse_args()?;
let call_expr = Box::new(Expr::Call(CallExpr {
span: span!(start),
callee: ExprOrSuper::Expr(callee),
args,
type_args,
}));
return self.parse_subscripts(ExprOrSuper::Expr(call_expr), false);
}
if type_args.is_some() {
expect!('(');
}
Ok(callee)
}
pub(super) fn parse_expr_or_pat(&mut self) -> PResult<'a, (Box<Expr>)> {
self.parse_expr()
}
pub(super) fn parse_args_or_pats(&mut self) -> PResult<'a, Vec<PatOrExprOrSpread>> {
expect!('(');
let mut first = true;
let mut items = vec![];
let mut rest_span = None;
while !eof!() && !is!(')') {
if first {
first = false;
} else {
expect!(',');
if is!(')') {
break;
}
}
let arg = {
if self.input.syntax().typescript()
&& (is!(IdentRef) || (is!("...") && peeked_is!(IdentRef)))
{
let spread = if eat!("...") {
Some(self.input.prev_span())
} else {
None
};
let expr = if spread.is_some() {
self.include_in_expr(true).parse_bin_expr()?
} else {
self.parse_bin_expr()?
};
ExprOrSpread { spread, expr }
} else {
self.include_in_expr(true).parse_expr_or_spread()?
}
};
let optional = if self.input.syntax().typescript() {
if eat!('?') {
match *arg.expr {
Expr::Ident(..) => {}
_ => syntax_error!(arg.span(), SyntaxError::TsBindingPatCannotBeOptional),
}
true
} else {
false
}
} else {
false
};
if optional || (self.input.syntax().typescript() && is!(':')) {
let start = cur_pos!();
let mut pat = self.reparse_expr_as_pat(PatType::BindingPat, arg.expr)?;
if optional {
match pat {
Pat::Ident(ref mut i) => i.optional = true,
_ => unreachable!(),
}
}
if let Some(span) = arg.spread {
if let Some(rest_span) = rest_span {
syntax_error!(rest_span, SyntaxError::NonLastRestParam);
}
rest_span = Some(span);
pat = Pat::Rest(RestPat {
dot3_token: span,
arg: Box::new(pat),
type_ann: None,
});
}
match pat {
Pat::Ident(Ident {
ref mut type_ann, ..
})
| Pat::Array(ArrayPat {
ref mut type_ann, ..
})
| Pat::Assign(AssignPat {
ref mut type_ann, ..
})
| Pat::Object(ObjectPat {
ref mut type_ann, ..
})
| Pat::Rest(RestPat {
ref mut type_ann, ..
}) => {
*type_ann = self
.parse_ts_type_ann( true, start)
.map(Some)?
}
Pat::Expr(ref expr) => unreachable!("invalid pattern: Expr({:?})", expr),
}
if eat!('=') {
let right = self.parse_expr()?;
pat = Pat::Assign(AssignPat {
span: span!(start),
left: Box::new(pat),
right,
type_ann: None,
});
}
items.push(PatOrExprOrSpread::Pat(pat))
} else {
items.push(PatOrExprOrSpread::ExprOrSpread(arg));
}
}
expect!(')');
Ok(items)
}
}
#[ast_node]
pub(in crate::parser) enum PatOrExprOrSpread {
Pat(Pat),
ExprOrSpread(ExprOrSpread),
}
#[parser]
impl<'a, I: Input> Parser<'a, I> {
fn parse_yield_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
assert_and_bump!("yield");
debug_assert!(self.ctx().in_generator);
if self.ctx().in_parameters {
syntax_error!(self.input.prev_span(), SyntaxError::YieldParamInGen)
}
if is!(';') || (!is!('*') && !cur!(false).map(Token::starts_expr).unwrap_or(true)) {
Ok(Box::new(Expr::Yield(YieldExpr {
span: span!(start),
arg: None,
delegate: false,
})))
} else {
let has_star = eat!('*');
let arg = self.parse_assignment_expr()?;
Ok(Box::new(Expr::Yield(YieldExpr {
span: span!(start),
arg: Some(arg),
delegate: has_star,
})))
}
}
fn at_possible_async(&mut self, expr: &Expr) -> PResult<'a, bool> {
Ok(self.state.potential_arrow_start == Some(expr.span().lo())
&& match *expr {
Expr::Ident(Ident {
sym: js_word!("async"),
..
}) => true,
_ => false,
})
}
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
let start = cur_pos!();
let v = match *cur!(true)? {
Word(Word::Null) => {
bump!();
let span = span!(start);
Lit::Null(Null { span })
}
Word(Word::True) | Word(Word::False) => {
let value = is!("true");
bump!();
let span = span!(start);
Lit::Bool(Bool { span, value })
}
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => Lit::Str(Str {
span: span!(start),
value,
has_escape,
}),
_ => unreachable!(),
},
Token::Num(..) => match bump!() {
Token::Num(value) => Lit::Num(Number {
span: span!(start),
value,
}),
_ => unreachable!(),
},
_ => unreachable!("parse_lit should not be called"),
};
Ok(v)
}
}