mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
parent
971aac5716
commit
96ad67db92
5 changed files with 56 additions and 48 deletions
|
|
@ -9,6 +9,10 @@ keywords.workspace = true
|
|||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lib]
|
||||
# We don't use doc tests because it's too slow
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
oxc_allocator = { workspace = true }
|
||||
oxc_ast = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -540,6 +540,16 @@ impl<'a> Parser<'a> {
|
|||
self.bump_any();
|
||||
self.ast.ts_non_null_expression(self.end_span(lhs_span), lhs)
|
||||
}
|
||||
kind if kind.is_template_start_of_tagged_template() => {
|
||||
let (expr, type_parameters) =
|
||||
if let Expression::TSInstantiationExpression(instantiation_expr) = lhs {
|
||||
let expr = instantiation_expr.unbox();
|
||||
(expr.expression, Some(expr.type_parameters))
|
||||
} else {
|
||||
(lhs, None)
|
||||
};
|
||||
self.parse_tagged_template(lhs_span, expr, *in_optional_chain, type_parameters)?
|
||||
}
|
||||
Kind::LAngle | Kind::ShiftLeft if self.ts_enabled() => {
|
||||
if let Some(arguments) = self.parse_ts_type_arguments_in_expression() {
|
||||
lhs = Expression::TSInstantiationExpression(self.ast.alloc(
|
||||
|
|
@ -647,60 +657,33 @@ impl<'a> Parser<'a> {
|
|||
in_optional_chain: &mut bool,
|
||||
) -> Result<Expression<'a>> {
|
||||
let mut lhs = lhs;
|
||||
let mut type_arguments = None;
|
||||
loop {
|
||||
let mut type_arguments = None;
|
||||
lhs = self.parse_member_expression_rhs(lhs_span, lhs, in_optional_chain)?;
|
||||
let optional_call = self.eat(Kind::QuestionDot);
|
||||
*in_optional_chain = if optional_call { true } else { *in_optional_chain };
|
||||
if let Expression::TSInstantiationExpression(expr) = lhs {
|
||||
let expr = expr.unbox();
|
||||
type_arguments.replace(expr.type_parameters);
|
||||
lhs = expr.expression;
|
||||
}
|
||||
match self.cur_kind() {
|
||||
Kind::LParen => {
|
||||
lhs = self.parse_call_arguments(
|
||||
lhs_span,
|
||||
lhs,
|
||||
optional_call,
|
||||
type_arguments.take(),
|
||||
)?;
|
||||
}
|
||||
Kind::NoSubstitutionTemplate | Kind::TemplateHead => {
|
||||
lhs = self.parse_tagged_template(
|
||||
lhs_span,
|
||||
lhs,
|
||||
*in_optional_chain,
|
||||
type_arguments.take(),
|
||||
)?;
|
||||
}
|
||||
Kind::LAngle | Kind::ShiftLeft if self.ts_enabled() => {
|
||||
let result = self.try_parse(|p| {
|
||||
let arguments = p.parse_ts_type_arguments()?;
|
||||
if p.at(Kind::RAngle) {
|
||||
// a<b>>c is not (a<b>)>c, but a<(b>>c)
|
||||
return Err(p.unexpected());
|
||||
}
|
||||
|
||||
// a<b>c is (a<b)>c
|
||||
if !p.at(Kind::LParen)
|
||||
&& !p.at(Kind::NoSubstitutionTemplate)
|
||||
&& !p.at(Kind::TemplateHead)
|
||||
&& p.cur_kind().is_at_expression()
|
||||
&& !p.cur_token().is_on_new_line
|
||||
{
|
||||
return Err(p.unexpected());
|
||||
}
|
||||
|
||||
type_arguments = arguments;
|
||||
Ok(())
|
||||
});
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
if optional_call {
|
||||
type_arguments = self.parse_ts_type_arguments_in_expression();
|
||||
if self.cur_kind().is_template_start_of_tagged_template() {
|
||||
lhs =
|
||||
self.parse_tagged_template(lhs_span, lhs, optional_call, type_arguments)?;
|
||||
continue;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
|
||||
if type_arguments.is_some() || self.at(Kind::LParen) {
|
||||
if let Expression::TSInstantiationExpression(expr) = lhs {
|
||||
let expr = expr.unbox();
|
||||
type_arguments.replace(expr.type_parameters);
|
||||
lhs = expr.expression;
|
||||
}
|
||||
|
||||
lhs =
|
||||
self.parse_call_arguments(lhs_span, lhs, optional_call, type_arguments.take())?;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(lhs)
|
||||
|
|
|
|||
|
|
@ -380,6 +380,11 @@ impl Kind {
|
|||
| Slash | SlashEq | TemplateHead | NoSubstitutionTemplate | PrivateIdentifier | Ident | Async)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_template_start_of_tagged_template(self) -> bool {
|
||||
matches!(self, NoSubstitutionTemplate | TemplateHead)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[rustfmt::skip]
|
||||
pub fn is_modifier_kind(self) -> bool {
|
||||
|
|
|
|||
|
|
@ -270,4 +270,19 @@ mod test {
|
|||
assert!(ret.program.is_empty());
|
||||
assert_eq!(ret.errors.first().unwrap().to_string(), "Flow is not supported");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzzer() {
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default();
|
||||
|
||||
let tests = [
|
||||
"1<(V=82<<t-j0<(V=$<LBI<(V=ut<I<(V=$<LBI<(V=uIV=82<<t-j0<(V=$<LBI<(V=ut<I<(V=$<LBI<(V<II>",
|
||||
];
|
||||
|
||||
for source in tests {
|
||||
let ret = Parser::new(&allocator, source, source_type).parse();
|
||||
assert!(!ret.errors.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,7 +507,8 @@ impl<'a> Parser<'a> {
|
|||
p.re_lex_ts_l_angle();
|
||||
|
||||
let params = TSTypeArgumentList::parse(p)?.params;
|
||||
if p.cur_kind().can_follow_type_arguments_in_expr() {
|
||||
let token = p.cur_token();
|
||||
if token.is_on_new_line || token.kind.can_follow_type_arguments_in_expr() {
|
||||
Ok(params)
|
||||
} else {
|
||||
Err(p.unexpected())
|
||||
|
|
|
|||
Loading…
Reference in a new issue