mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
refactor(parser): improve expression parsing (#3352)
This commit is contained in:
parent
e818fba21c
commit
89a1f97320
8 changed files with 192 additions and 129 deletions
|
|
@ -1770,6 +1770,20 @@ impl<'a> AstBuilder<'a> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ts_instantiation_expression(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
expression: Expression<'a>,
|
||||||
|
type_parameters: Box<'a, TSTypeParameterInstantiation<'a>>,
|
||||||
|
) -> Expression<'a> {
|
||||||
|
Expression::TSInstantiationExpression(self.alloc(TSInstantiationExpression {
|
||||||
|
span,
|
||||||
|
expression,
|
||||||
|
type_parameters,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ts_non_null_expression(&self, span: Span, expression: Expression<'a>) -> Expression<'a> {
|
pub fn ts_non_null_expression(&self, span: Span, expression: Expression<'a>) -> Expression<'a> {
|
||||||
Expression::TSNonNullExpression(self.alloc(TSNonNullExpression { span, expression }))
|
Expression::TSNonNullExpression(self.alloc(TSNonNullExpression { span, expression }))
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ use oxc_allocator::Box;
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
use oxc_diagnostics::Result;
|
use oxc_diagnostics::Result;
|
||||||
use oxc_span::{GetSpan, Span};
|
use oxc_span::{GetSpan, Span};
|
||||||
|
use oxc_syntax::precedence::Precedence;
|
||||||
|
|
||||||
use crate::{diagnostics, lexer::Kind, AstBuilder, ParserImpl};
|
use crate::{diagnostics, lexer::Kind, ParserImpl};
|
||||||
|
|
||||||
use super::Tristate;
|
use super::Tristate;
|
||||||
|
|
||||||
|
|
@ -34,8 +35,9 @@ impl<'a> ParserImpl<'a> {
|
||||||
{
|
{
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
self.bump_any(); // bump `async`
|
self.bump_any(); // bump `async`
|
||||||
|
let expr = self.parse_binary_expression_or_higher(Precedence::lowest())?;
|
||||||
return self
|
return self
|
||||||
.parse_simple_arrow_function_expression(span, /* is_async */ true)
|
.parse_simple_arrow_function_expression(span, expr, /* async */ true)
|
||||||
.map(Some);
|
.map(Some);
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|
@ -186,7 +188,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
// Check for un-parenthesized AsyncArrowFunction
|
// Check for un-parenthesized AsyncArrowFunction
|
||||||
if first.is_binding_identifier() {
|
if first.is_binding_identifier() {
|
||||||
// Arrow before newline is checkedin `parse_simple_arrow_function_expression`
|
// Arrow before newline is checked in `parse_simple_arrow_function_expression`
|
||||||
if self.nth_at(2, Kind::Arrow) {
|
if self.nth_at(2, Kind::Arrow) {
|
||||||
return Tristate::True;
|
return Tristate::True;
|
||||||
}
|
}
|
||||||
|
|
@ -198,24 +200,24 @@ impl<'a> ParserImpl<'a> {
|
||||||
pub(crate) fn parse_simple_arrow_function_expression(
|
pub(crate) fn parse_simple_arrow_function_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
ident: Expression<'a>,
|
||||||
r#async: bool,
|
r#async: bool,
|
||||||
) -> Result<Expression<'a>> {
|
) -> Result<Expression<'a>> {
|
||||||
let has_await = self.ctx.has_await();
|
let has_await = self.ctx.has_await();
|
||||||
self.ctx = self.ctx.union_await_if(r#async);
|
self.ctx = self.ctx.union_await_if(r#async);
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
let params_span = self.start_span();
|
let ident = match ident {
|
||||||
let param = self.parse_binding_identifier()?;
|
Expression::Identifier(ident) => {
|
||||||
let ident = self.ast.binding_pattern_identifier(param);
|
let name = ident.name.clone();
|
||||||
let params_span = self.end_span(params_span);
|
BindingIdentifier::new(ident.span, name)
|
||||||
let formal_parameter = self.ast.formal_parameter(
|
}
|
||||||
params_span,
|
_ => unreachable!(),
|
||||||
self.ast.binding_pattern(ident, None, false),
|
};
|
||||||
None,
|
let params_span = self.end_span(ident.span);
|
||||||
false,
|
let ident = self.ast.binding_pattern_identifier(ident);
|
||||||
false,
|
let pattern = self.ast.binding_pattern(ident, None, false);
|
||||||
AstBuilder::new_vec(&self.ast),
|
let formal_parameter = self.ast.plain_formal_parameter(params_span, pattern);
|
||||||
);
|
|
||||||
self.ast.formal_parameters(
|
self.ast.formal_parameters(
|
||||||
params_span,
|
params_span,
|
||||||
FormalParameterKind::ArrowFormalParameters,
|
FormalParameterKind::ArrowFormalParameters,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
let mut extends = self.ast.new_vec();
|
let mut extends = self.ast.new_vec();
|
||||||
|
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let mut first_extends = self.parse_lhs_expression()?;
|
let mut first_extends = self.parse_lhs_expression_or_higher()?;
|
||||||
let first_type_argument;
|
let first_type_argument;
|
||||||
if let Expression::TSInstantiationExpression(expr) = first_extends {
|
if let Expression::TSInstantiationExpression(expr) = first_extends {
|
||||||
let expr = expr.unbox();
|
let expr = expr.unbox();
|
||||||
|
|
@ -135,7 +135,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
|
|
||||||
while self.eat(Kind::Comma) {
|
while self.eat(Kind::Comma) {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let mut extend = self.parse_lhs_expression()?;
|
let mut extend = self.parse_lhs_expression_or_higher()?;
|
||||||
let type_argument;
|
let type_argument;
|
||||||
if let Expression::TSInstantiationExpression(expr) = extend {
|
if let Expression::TSInstantiationExpression(expr) = extend {
|
||||||
let expr = expr.unbox();
|
let expr = expr.unbox();
|
||||||
|
|
|
||||||
|
|
@ -115,11 +115,11 @@ impl<'a> ParserImpl<'a> {
|
||||||
|
|
||||||
pub(crate) fn check_identifier(&mut self, span: Span, name: &Atom) {
|
pub(crate) fn check_identifier(&mut self, span: Span, name: &Atom) {
|
||||||
// It is a Syntax Error if this production has an [Await] parameter.
|
// It is a Syntax Error if this production has an [Await] parameter.
|
||||||
if self.ctx.has_await() && *name == "await" {
|
if self.ctx.has_await() && name.as_str() == "await" {
|
||||||
self.error(diagnostics::identifier_async("await", span));
|
self.error(diagnostics::identifier_async("await", span));
|
||||||
}
|
}
|
||||||
// It is a Syntax Error if this production has a [Yield] parameter.
|
// It is a Syntax Error if this production has a [Yield] parameter.
|
||||||
if self.ctx.has_yield() && *name == "yield" {
|
if self.ctx.has_yield() && name.as_str() == "yield" {
|
||||||
self.error(diagnostics::identifier_generator("yield", span));
|
self.error(diagnostics::identifier_generator("yield", span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -498,11 +498,11 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.3 Left-Hand-Side Expression
|
/// Section 13.3 Left-Hand-Side Expression
|
||||||
pub(crate) fn parse_lhs_expression(&mut self) -> Result<Expression<'a>> {
|
pub(crate) fn parse_lhs_expression_or_higher(&mut self) -> Result<Expression<'a>> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let mut in_optional_chain = false;
|
let mut in_optional_chain = false;
|
||||||
let lhs = self.parse_member_expression_base(&mut in_optional_chain)?;
|
let lhs = self.parse_member_expression_or_higher(&mut in_optional_chain)?;
|
||||||
let lhs = self.parse_call_expression(span, lhs, &mut in_optional_chain)?;
|
let lhs = self.parse_call_expression_rest(span, lhs, &mut in_optional_chain)?;
|
||||||
if in_optional_chain {
|
if in_optional_chain {
|
||||||
let span = self.end_span(span);
|
let span = self.end_span(span);
|
||||||
Ok(self.map_to_chain_expression(span, lhs))
|
Ok(self.map_to_chain_expression(span, lhs))
|
||||||
|
|
@ -525,13 +525,13 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.3 Member Expression
|
/// Section 13.3 Member Expression
|
||||||
fn parse_member_expression_base(
|
fn parse_member_expression_or_higher(
|
||||||
&mut self,
|
&mut self,
|
||||||
in_optional_chain: &mut bool,
|
in_optional_chain: &mut bool,
|
||||||
) -> Result<Expression<'a>> {
|
) -> Result<Expression<'a>> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
self.parse_primary_expression()
|
self.parse_primary_expression()
|
||||||
.and_then(|lhs| self.parse_member_expression_rhs(span, lhs, in_optional_chain))
|
.and_then(|lhs| self.parse_member_expression_rest(span, lhs, in_optional_chain))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.3 Super Call
|
/// Section 13.3 Super Call
|
||||||
|
|
@ -554,7 +554,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parse rhs of a member expression, starting from lhs
|
/// parse rhs of a member expression, starting from lhs
|
||||||
fn parse_member_expression_rhs(
|
fn parse_member_expression_rest(
|
||||||
&mut self,
|
&mut self,
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
lhs: Expression<'a>,
|
lhs: Expression<'a>,
|
||||||
|
|
@ -600,15 +600,15 @@ impl<'a> ParserImpl<'a> {
|
||||||
};
|
};
|
||||||
self.parse_tagged_template(lhs_span, expr, *in_optional_chain, type_parameters)?
|
self.parse_tagged_template(lhs_span, expr, *in_optional_chain, type_parameters)?
|
||||||
}
|
}
|
||||||
Kind::LAngle | Kind::ShiftLeft if self.ts_enabled() => {
|
Kind::LAngle | Kind::ShiftLeft => {
|
||||||
if let Some(arguments) = self.parse_ts_type_arguments_in_expression() {
|
if let Ok(Some(arguments)) =
|
||||||
lhs = Expression::TSInstantiationExpression(self.ast.alloc(
|
self.try_parse(Self::parse_ts_type_arguments_in_expression)
|
||||||
TSInstantiationExpression {
|
{
|
||||||
span: self.end_span(lhs_span),
|
lhs = self.ast.ts_instantiation_expression(
|
||||||
expression: lhs,
|
self.end_span(lhs_span),
|
||||||
type_parameters: arguments,
|
lhs,
|
||||||
},
|
arguments,
|
||||||
));
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -667,7 +667,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
let rhs_span = self.start_span();
|
let rhs_span = self.start_span();
|
||||||
|
|
||||||
let mut optional = false;
|
let mut optional = false;
|
||||||
let mut callee = self.parse_member_expression_base(&mut optional)?;
|
let mut callee = self.parse_member_expression_or_higher(&mut optional)?;
|
||||||
|
|
||||||
let mut type_parameter = None;
|
let mut type_parameter = None;
|
||||||
if let Expression::TSInstantiationExpression(instantiation_expr) = callee {
|
if let Expression::TSInstantiationExpression(instantiation_expr) = callee {
|
||||||
|
|
@ -699,7 +699,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.3 Call Expression
|
/// Section 13.3 Call Expression
|
||||||
fn parse_call_expression(
|
fn parse_call_expression_rest(
|
||||||
&mut self,
|
&mut self,
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
lhs: Expression<'a>,
|
lhs: Expression<'a>,
|
||||||
|
|
@ -708,12 +708,15 @@ impl<'a> ParserImpl<'a> {
|
||||||
let mut lhs = lhs;
|
let mut lhs = lhs;
|
||||||
loop {
|
loop {
|
||||||
let mut type_arguments = None;
|
let mut type_arguments = None;
|
||||||
lhs = self.parse_member_expression_rhs(lhs_span, lhs, in_optional_chain)?;
|
lhs = self.parse_member_expression_rest(lhs_span, lhs, in_optional_chain)?;
|
||||||
let optional_call = self.eat(Kind::QuestionDot);
|
let optional_call = self.eat(Kind::QuestionDot);
|
||||||
*in_optional_chain = if optional_call { true } else { *in_optional_chain };
|
*in_optional_chain = if optional_call { true } else { *in_optional_chain };
|
||||||
|
|
||||||
if optional_call {
|
if optional_call {
|
||||||
type_arguments = self.parse_ts_type_arguments_in_expression();
|
if let Ok(Some(args)) = self.try_parse(Self::parse_ts_type_arguments_in_expression)
|
||||||
|
{
|
||||||
|
type_arguments = Some(args);
|
||||||
|
}
|
||||||
if self.cur_kind().is_template_start_of_tagged_template() {
|
if self.cur_kind().is_template_start_of_tagged_template() {
|
||||||
lhs =
|
lhs =
|
||||||
self.parse_tagged_template(lhs_span, lhs, optional_call, type_arguments)?;
|
self.parse_tagged_template(lhs_span, lhs, optional_call, type_arguments)?;
|
||||||
|
|
@ -758,9 +761,31 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.4 Update Expression
|
/// Section 13.4 Update Expression
|
||||||
fn parse_update_expression(&mut self) -> Result<Expression<'a>> {
|
fn parse_update_expression(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
|
||||||
|
let kind = self.cur_kind();
|
||||||
|
// ++ -- prefix update expressions
|
||||||
|
if kind.is_update_operator() {
|
||||||
|
let operator = map_update_operator(kind);
|
||||||
|
self.bump_any();
|
||||||
|
let argument = self.parse_unary_expression_or_higher(lhs_span)?;
|
||||||
|
let argument = SimpleAssignmentTarget::cover(argument, self)?;
|
||||||
|
return Ok(self.ast.update_expression(
|
||||||
|
self.end_span(lhs_span),
|
||||||
|
operator,
|
||||||
|
true,
|
||||||
|
argument,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.source_type.is_jsx()
|
||||||
|
&& kind == Kind::LAngle
|
||||||
|
&& self.peek_kind().is_identifier_name()
|
||||||
|
{
|
||||||
|
return self.parse_jsx_expression();
|
||||||
|
}
|
||||||
|
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let lhs = self.parse_lhs_expression()?;
|
let lhs = self.parse_lhs_expression_or_higher()?;
|
||||||
// ++ -- postfix update expressions
|
// ++ -- postfix update expressions
|
||||||
if self.cur_kind().is_update_operator() && !self.cur_token().is_on_new_line {
|
if self.cur_kind().is_update_operator() && !self.cur_token().is_on_new_line {
|
||||||
let operator = map_update_operator(self.cur_kind());
|
let operator = map_update_operator(self.cur_kind());
|
||||||
|
|
@ -772,50 +797,46 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.5 Unary Expression
|
/// Section 13.5 Unary Expression
|
||||||
pub(crate) fn parse_unary_expression_base(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
|
pub(crate) fn parse_unary_expression_or_higher(
|
||||||
// [+Await] AwaitExpression
|
&mut self,
|
||||||
if self.is_await_expression() {
|
lhs_span: Span,
|
||||||
return self.parse_await_expression(lhs_span);
|
) -> Result<Expression<'a>> {
|
||||||
}
|
|
||||||
|
|
||||||
if (self.at(Kind::LAngle) || self.at(Kind::ShiftLeft))
|
|
||||||
&& !self.source_type.is_jsx()
|
|
||||||
&& self.ts_enabled()
|
|
||||||
{
|
|
||||||
return self.parse_ts_type_assertion();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ++ -- prefix update expressions
|
// ++ -- prefix update expressions
|
||||||
if self.cur_kind().is_update_operator() {
|
if self.is_update_expression() {
|
||||||
let operator = map_update_operator(self.cur_kind());
|
return self.parse_update_expression(lhs_span);
|
||||||
self.bump_any();
|
|
||||||
let argument = self.parse_unary_expression_base(lhs_span)?;
|
|
||||||
let argument = SimpleAssignmentTarget::cover(argument, self)?;
|
|
||||||
return Ok(self.ast.update_expression(
|
|
||||||
self.end_span(lhs_span),
|
|
||||||
operator,
|
|
||||||
true,
|
|
||||||
argument,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
self.parse_simple_unary_expression(lhs_span)
|
||||||
|
}
|
||||||
|
|
||||||
// delete void typeof + - ~ ! prefix unary expressions
|
pub(crate) fn parse_simple_unary_expression(
|
||||||
if self.cur_kind().is_unary_operator() {
|
&mut self,
|
||||||
return self.parse_unary_expression();
|
lhs_span: Span,
|
||||||
|
) -> Result<Expression<'a>> {
|
||||||
|
match self.cur_kind() {
|
||||||
|
kind if kind.is_unary_operator() => self.parse_unary_expression(),
|
||||||
|
Kind::LAngle => {
|
||||||
|
if self.source_type.is_jsx() {
|
||||||
|
return self.parse_jsx_expression();
|
||||||
|
}
|
||||||
|
if self.ts_enabled() {
|
||||||
|
return self.parse_ts_type_assertion();
|
||||||
|
}
|
||||||
|
Err(self.unexpected())
|
||||||
|
}
|
||||||
|
Kind::Await if self.is_await_expression() => self.parse_await_expression(lhs_span),
|
||||||
|
_ => self.parse_update_expression(lhs_span),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parse_update_expression()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary_expression(&mut self) -> Result<Expression<'a>> {
|
fn parse_unary_expression(&mut self) -> Result<Expression<'a>> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let operator = map_unary_operator(self.cur_kind());
|
let operator = map_unary_operator(self.cur_kind());
|
||||||
self.bump_any();
|
self.bump_any();
|
||||||
let argument = self.parse_unary_expression_base(span)?;
|
let argument = self.parse_simple_unary_expression(span)?;
|
||||||
Ok(self.ast.unary_expression(self.end_span(span), operator, argument))
|
Ok(self.ast.unary_expression(self.end_span(span), operator, argument))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_binary_or_logical_expression_base(
|
pub(crate) fn parse_binary_expression_or_higher(
|
||||||
&mut self,
|
&mut self,
|
||||||
lhs_precedence: Precedence,
|
lhs_precedence: Precedence,
|
||||||
) -> Result<Expression<'a>> {
|
) -> Result<Expression<'a>> {
|
||||||
|
|
@ -824,7 +845,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
let lhs = if self.ctx.has_in() && self.at(Kind::PrivateIdentifier) {
|
let lhs = if self.ctx.has_in() && self.at(Kind::PrivateIdentifier) {
|
||||||
let left = self.parse_private_identifier();
|
let left = self.parse_private_identifier();
|
||||||
self.expect(Kind::In)?;
|
self.expect(Kind::In)?;
|
||||||
let right = self.parse_unary_expression_base(lhs_span)?;
|
let right = self.parse_unary_expression_or_higher(lhs_span)?;
|
||||||
Expression::PrivateInExpression(self.ast.alloc(PrivateInExpression {
|
Expression::PrivateInExpression(self.ast.alloc(PrivateInExpression {
|
||||||
span: self.end_span(lhs_span),
|
span: self.end_span(lhs_span),
|
||||||
left,
|
left,
|
||||||
|
|
@ -832,14 +853,14 @@ impl<'a> ParserImpl<'a> {
|
||||||
right,
|
right,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
self.parse_unary_expression_base(lhs_span)?
|
self.parse_unary_expression_or_higher(lhs_span)?
|
||||||
};
|
};
|
||||||
|
|
||||||
self.parse_binary_or_logical_expression_recursive(lhs_span, lhs, lhs_precedence)
|
self.parse_binary_expression_rest(lhs_span, lhs, lhs_precedence)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Section 13.6 - 13.13 Binary Expression
|
/// Section 13.6 - 13.13 Binary Expression
|
||||||
fn parse_binary_or_logical_expression_recursive(
|
fn parse_binary_expression_rest(
|
||||||
&mut self,
|
&mut self,
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
lhs: Expression<'a>,
|
lhs: Expression<'a>,
|
||||||
|
|
@ -888,7 +909,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bump_any(); // bump operator
|
self.bump_any(); // bump operator
|
||||||
let rhs = self.parse_binary_or_logical_expression_base(left_precedence)?;
|
let rhs = self.parse_binary_expression_or_higher(left_precedence)?;
|
||||||
|
|
||||||
lhs = if kind.is_logical_operator() {
|
lhs = if kind.is_logical_operator() {
|
||||||
self.ast.logical_expression(
|
self.ast.logical_expression(
|
||||||
|
|
@ -916,9 +937,11 @@ impl<'a> ParserImpl<'a> {
|
||||||
/// `ConditionalExpression`[In, Yield, Await] :
|
/// `ConditionalExpression`[In, Yield, Await] :
|
||||||
/// `ShortCircuitExpression`[?In, ?Yield, ?Await]
|
/// `ShortCircuitExpression`[?In, ?Yield, ?Await]
|
||||||
/// `ShortCircuitExpression`[?In, ?Yield, ?Await] ? `AssignmentExpression`[+In, ?Yield, ?Await] : `AssignmentExpression`[?In, ?Yield, ?Await]
|
/// `ShortCircuitExpression`[?In, ?Yield, ?Await] ? `AssignmentExpression`[+In, ?Yield, ?Await] : `AssignmentExpression`[?In, ?Yield, ?Await]
|
||||||
fn parse_conditional_expression(&mut self) -> Result<Expression<'a>> {
|
fn parse_conditional_expression_rest(
|
||||||
let span = self.start_span();
|
&mut self,
|
||||||
let lhs = self.parse_binary_or_logical_expression_base(Precedence::lowest())?;
|
lhs_span: Span,
|
||||||
|
lhs: Expression<'a>,
|
||||||
|
) -> Result<Expression<'a>> {
|
||||||
if !self.eat(Kind::Question) {
|
if !self.eat(Kind::Question) {
|
||||||
return Ok(lhs);
|
return Ok(lhs);
|
||||||
}
|
}
|
||||||
|
|
@ -929,7 +952,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
)?;
|
)?;
|
||||||
self.expect(Kind::Colon)?;
|
self.expect(Kind::Colon)?;
|
||||||
let alternate = self.parse_assignment_expression_or_higher()?;
|
let alternate = self.parse_assignment_expression_or_higher()?;
|
||||||
Ok(self.ast.conditional_expression(self.end_span(span), lhs, consequent, alternate))
|
Ok(self.ast.conditional_expression(self.end_span(lhs_span), lhs, consequent, alternate))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `AssignmentExpression`[In, Yield, Await] :
|
/// `AssignmentExpression`[In, Yield, Await] :
|
||||||
|
|
@ -946,13 +969,21 @@ impl<'a> ParserImpl<'a> {
|
||||||
if let Some(arrow_expr) = self.try_parse_async_simple_arrow_function_expression()? {
|
if let Some(arrow_expr) = self.try_parse_async_simple_arrow_function_expression()? {
|
||||||
return Ok(arrow_expr);
|
return Ok(arrow_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
|
let lhs = self.parse_binary_expression_or_higher(Precedence::lowest())?;
|
||||||
|
let kind = self.cur_kind();
|
||||||
|
|
||||||
// `x => {}`
|
// `x => {}`
|
||||||
if self.cur_kind().is_binding_identifier() && self.peek_at(Kind::Arrow) {
|
if lhs.is_identifier_reference() && kind == Kind::Arrow {
|
||||||
return self.parse_simple_arrow_function_expression(span, /* r#async */ false);
|
return self.parse_simple_arrow_function_expression(span, lhs, /* async */ false);
|
||||||
}
|
}
|
||||||
let lhs = self.parse_conditional_expression()?;
|
|
||||||
self.parse_assignment_expression_recursive(span, lhs)
|
if kind.is_assignment_operator() {
|
||||||
|
return self.parse_assignment_expression_recursive(span, lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parse_conditional_expression_rest(span, lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_assignment_expression_recursive(
|
fn parse_assignment_expression_recursive(
|
||||||
|
|
@ -960,12 +991,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
lhs: Expression<'a>,
|
lhs: Expression<'a>,
|
||||||
) -> Result<Expression<'a>> {
|
) -> Result<Expression<'a>> {
|
||||||
if !self.cur_kind().is_assignment_operator() {
|
|
||||||
return Ok(lhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let operator = map_assignment_operator(self.cur_kind());
|
let operator = map_assignment_operator(self.cur_kind());
|
||||||
|
|
||||||
// 13.15.5 Destructuring Assignment
|
// 13.15.5 Destructuring Assignment
|
||||||
// LeftHandSideExpression = AssignmentExpression
|
// LeftHandSideExpression = AssignmentExpression
|
||||||
// is converted to
|
// is converted to
|
||||||
|
|
@ -973,9 +999,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
// ObjectAssignmentPattern
|
// ObjectAssignmentPattern
|
||||||
// ArrayAssignmentPattern
|
// ArrayAssignmentPattern
|
||||||
let left = AssignmentTarget::cover(lhs, self)?;
|
let left = AssignmentTarget::cover(lhs, self)?;
|
||||||
|
|
||||||
self.bump_any();
|
self.bump_any();
|
||||||
|
|
||||||
let right = self.parse_assignment_expression_or_higher()?;
|
let right = self.parse_assignment_expression_or_higher()?;
|
||||||
Ok(self.ast.assignment_expression(self.end_span(span), operator, left, right))
|
Ok(self.ast.assignment_expression(self.end_span(span), operator, left, right))
|
||||||
}
|
}
|
||||||
|
|
@ -1004,7 +1028,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5)));
|
self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5)));
|
||||||
}
|
}
|
||||||
let argument = self.context(Context::Await, Context::empty(), |p| {
|
let argument = self.context(Context::Await, Context::empty(), |p| {
|
||||||
p.parse_unary_expression_base(lhs_span)
|
p.parse_simple_unary_expression(lhs_span)
|
||||||
})?;
|
})?;
|
||||||
Ok(self.ast.await_expression(self.end_span(span), argument))
|
Ok(self.ast.await_expression(self.end_span(span), argument))
|
||||||
}
|
}
|
||||||
|
|
@ -1016,18 +1040,38 @@ impl<'a> ParserImpl<'a> {
|
||||||
pub(crate) fn parse_decorator(&mut self) -> Result<Decorator<'a>> {
|
pub(crate) fn parse_decorator(&mut self) -> Result<Decorator<'a>> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
self.bump_any(); // bump @
|
self.bump_any(); // bump @
|
||||||
let expr =
|
let expr = self.context(
|
||||||
self.context(Context::Decorator, Context::empty(), Self::parse_lhs_expression)?;
|
Context::Decorator,
|
||||||
|
Context::empty(),
|
||||||
|
Self::parse_lhs_expression_or_higher,
|
||||||
|
)?;
|
||||||
Ok(self.ast.decorator(self.end_span(span), expr))
|
Ok(self.ast.decorator(self.end_span(span), expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_update_expression(&self) -> bool {
|
||||||
|
match self.cur_kind() {
|
||||||
|
kind if kind.is_unary_operator() => false,
|
||||||
|
Kind::Await => false,
|
||||||
|
Kind::LAngle => {
|
||||||
|
if !self.source_type.is_jsx() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_await_expression(&mut self) -> bool {
|
fn is_await_expression(&mut self) -> bool {
|
||||||
if self.at(Kind::Await) {
|
if self.at(Kind::Await) {
|
||||||
|
let peek_token = self.peek_token();
|
||||||
|
// Allow arrow expression `await => {}`
|
||||||
|
if peek_token.kind == Kind::Arrow {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if self.ctx.has_await() {
|
if self.ctx.has_await() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let peek_token = self.peek_token();
|
|
||||||
// The following expressions are ambiguous
|
// The following expressions are ambiguous
|
||||||
// await + 0, await - 0, await ( 0 ), await [ 0 ], await / 0 /u, await ``, await of []
|
// await + 0, await - 0, await ( 0 ), await [ 0 ], await / 0 /u, await ``, await of []
|
||||||
if matches!(
|
if matches!(
|
||||||
|
|
@ -1037,7 +1081,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return peek_token.kind.is_after_await_or_yield() && !peek_token.is_on_new_line;
|
return !peek_token.is_on_new_line && peek_token.kind.is_after_await_or_yield();
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -1045,13 +1089,14 @@ impl<'a> ParserImpl<'a> {
|
||||||
fn is_yield_expression(&mut self) -> bool {
|
fn is_yield_expression(&mut self) -> bool {
|
||||||
if self.at(Kind::Yield) {
|
if self.at(Kind::Yield) {
|
||||||
let peek_token = self.peek_token();
|
let peek_token = self.peek_token();
|
||||||
|
// Allow arrow expression `yield => {}`
|
||||||
if peek_token.kind == Kind::Arrow {
|
if peek_token.kind == Kind::Arrow {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if self.ctx.has_yield() {
|
if self.ctx.has_yield() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return peek_token.kind.is_after_await_or_yield() && !peek_token.is_on_new_line;
|
return !peek_token.is_on_new_line && peek_token.kind.is_after_await_or_yield();
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
let type_annotation = self.parse_ts_type()?;
|
let type_annotation = self.parse_ts_type()?;
|
||||||
self.expect(Kind::RAngle)?;
|
self.expect(Kind::RAngle)?;
|
||||||
let lhs_span = self.start_span();
|
let lhs_span = self.start_span();
|
||||||
let expression = self.parse_unary_expression_base(lhs_span)?;
|
let expression = self.parse_simple_unary_expression(lhs_span)?;
|
||||||
Ok(self.ast.ts_type_assertion(self.end_span(span), type_annotation, expression))
|
Ok(self.ast.ts_type_assertion(self.end_span(span), type_annotation, expression))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -532,25 +532,26 @@ impl<'a> ParserImpl<'a> {
|
||||||
|
|
||||||
pub(crate) fn parse_ts_type_arguments_in_expression(
|
pub(crate) fn parse_ts_type_arguments_in_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Option<Box<'a, TSTypeParameterInstantiation<'a>>> {
|
) -> Result<Option<Box<'a, TSTypeParameterInstantiation<'a>>>> {
|
||||||
if !matches!(self.cur_kind(), Kind::LAngle | Kind::ShiftLeft) {
|
if !self.ts_enabled() {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
|
self.re_lex_ts_l_angle();
|
||||||
|
if !self.at(Kind::LAngle) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
self.try_parse(|p| {
|
let params = TSTypeArgumentList::parse(self, /* in_expression */ true)?.params;
|
||||||
p.re_lex_ts_l_angle();
|
|
||||||
|
|
||||||
let params = TSTypeArgumentList::parse(p, true)?.params;
|
let token = self.cur_token();
|
||||||
let token = p.cur_token();
|
|
||||||
if token.is_on_new_line || token.kind.can_follow_type_arguments_in_expr() {
|
if token.is_on_new_line || token.kind.can_follow_type_arguments_in_expr() {
|
||||||
Ok(params)
|
return Ok(Some(self.ast.ts_type_arguments(self.end_span(span), params)));
|
||||||
} else {
|
}
|
||||||
Err(p.unexpected())
|
|
||||||
}
|
Err(self.unexpected())
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.map(|types| self.ast.ts_type_arguments(self.end_span(span), types))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ts_tuple_type(&mut self) -> Result<TSType<'a>> {
|
fn parse_ts_tuple_type(&mut self) -> Result<TSType<'a>> {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ commit: 4bd1b2c2
|
||||||
parser_babel Summary:
|
parser_babel Summary:
|
||||||
AST Parsed : 2093/2099 (99.71%)
|
AST Parsed : 2093/2099 (99.71%)
|
||||||
Positive Passed: 2086/2099 (99.38%)
|
Positive Passed: 2086/2099 (99.38%)
|
||||||
Negative Passed: 1363/1501 (90.81%)
|
Negative Passed: 1362/1501 (90.74%)
|
||||||
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
|
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
|
||||||
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
|
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
|
||||||
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
|
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
|
||||||
|
|
@ -25,6 +25,7 @@ Expect Syntax Error: "es2015/for-of/invalid-let-as-identifier/input.js"
|
||||||
Expect Syntax Error: "es2015/object/disallow-duplicate-method-params/input.js"
|
Expect Syntax Error: "es2015/object/disallow-duplicate-method-params/input.js"
|
||||||
Expect Syntax Error: "es2015/uncategorised/297/input.js"
|
Expect Syntax Error: "es2015/uncategorised/297/input.js"
|
||||||
Expect Syntax Error: "es2015/uncategorised/335/input.js"
|
Expect Syntax Error: "es2015/uncategorised/335/input.js"
|
||||||
|
Expect Syntax Error: "es2017/async-functions/async-await-as-arrow-binding-identifier/input.js"
|
||||||
Expect Syntax Error: "es2017/async-functions/await-binding-inside-arrow-params-inside-async-arrow-params/input.js"
|
Expect Syntax Error: "es2017/async-functions/await-binding-inside-arrow-params-inside-async-arrow-params/input.js"
|
||||||
Expect Syntax Error: "es2017/trailing-function-commas/7/input.js"
|
Expect Syntax Error: "es2017/trailing-function-commas/7/input.js"
|
||||||
Expect Syntax Error: "es2018/object-rest-spread/24/input.js"
|
Expect Syntax Error: "es2018/object-rest-spread/24/input.js"
|
||||||
|
|
@ -4842,12 +4843,6 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
|
||||||
3 │ }
|
3 │ }
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
× Cannot use `await` as an identifier in an async context
|
|
||||||
╭─[es2017/async-functions/async-await-as-arrow-binding-identifier/input.js:1:7]
|
|
||||||
1 │ async await => {}
|
|
||||||
· ─────
|
|
||||||
╰────
|
|
||||||
|
|
||||||
× Expected a semicolon or an implicit semicolon after a statement, but found none
|
× Expected a semicolon or an implicit semicolon after a statement, but found none
|
||||||
╭─[es2017/async-functions/async-function-and-non-bmp-character/input.js:1:6]
|
╭─[es2017/async-functions/async-function-and-non-bmp-character/input.js:1:6]
|
||||||
1 │ async function𝐬 f() {}
|
1 │ async function𝐬 f() {}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ commit: 64d2eeea
|
||||||
parser_typescript Summary:
|
parser_typescript Summary:
|
||||||
AST Parsed : 5240/5243 (99.94%)
|
AST Parsed : 5240/5243 (99.94%)
|
||||||
Positive Passed: 5233/5243 (99.81%)
|
Positive Passed: 5233/5243 (99.81%)
|
||||||
Negative Passed: 1064/4879 (21.81%)
|
Negative Passed: 1065/4879 (21.83%)
|
||||||
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
|
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
|
||||||
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
|
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
|
||||||
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
|
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
|
||||||
|
|
@ -58,7 +58,6 @@ Expect Syntax Error: "compiler/ambientExternalModuleWithRelativeModuleName.ts"
|
||||||
Expect Syntax Error: "compiler/ambientGetters.ts"
|
Expect Syntax Error: "compiler/ambientGetters.ts"
|
||||||
Expect Syntax Error: "compiler/ambientPropertyDeclarationInJs.ts"
|
Expect Syntax Error: "compiler/ambientPropertyDeclarationInJs.ts"
|
||||||
Expect Syntax Error: "compiler/ambientStatement1.ts"
|
Expect Syntax Error: "compiler/ambientStatement1.ts"
|
||||||
Expect Syntax Error: "compiler/ambiguousGenericAssertion1.ts"
|
|
||||||
Expect Syntax Error: "compiler/ambiguousOverload.ts"
|
Expect Syntax Error: "compiler/ambiguousOverload.ts"
|
||||||
Expect Syntax Error: "compiler/amdDependencyComment1.ts"
|
Expect Syntax Error: "compiler/amdDependencyComment1.ts"
|
||||||
Expect Syntax Error: "compiler/amdDependencyComment2.ts"
|
Expect Syntax Error: "compiler/amdDependencyComment2.ts"
|
||||||
|
|
@ -4123,6 +4122,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
||||||
26 │ }
|
26 │ }
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
× Unexpected token
|
||||||
|
╭─[compiler/ambiguousGenericAssertion1.ts:4:10]
|
||||||
|
3 │ var r2 = < <T>(x: T) => T>f; // valid
|
||||||
|
4 │ var r3 = <<T>(x: T) => T>f; // ambiguous, appears to the parser as a << operation
|
||||||
|
· ──
|
||||||
|
╰────
|
||||||
|
|
||||||
× Expected a semicolon or an implicit semicolon after a statement, but found none
|
× Expected a semicolon or an implicit semicolon after a statement, but found none
|
||||||
╭─[compiler/anonymousModules.ts:1:7]
|
╭─[compiler/anonymousModules.ts:1:7]
|
||||||
1 │ module {
|
1 │ module {
|
||||||
|
|
@ -5365,10 +5371,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
× Unexpected token
|
× Unexpected token
|
||||||
╭─[compiler/conflictMarkerDiff3Trivia2.ts:3:2]
|
╭─[compiler/conflictMarkerDiff3Trivia2.ts:3:1]
|
||||||
2 │ foo() {
|
2 │ foo() {
|
||||||
3 │ <<<<<<< B
|
3 │ <<<<<<< B
|
||||||
· ──
|
· ──
|
||||||
4 │ a();
|
4 │ a();
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
|
@ -5381,10 +5387,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
× Unexpected token
|
× Unexpected token
|
||||||
╭─[compiler/conflictMarkerTrivia2.ts:3:2]
|
╭─[compiler/conflictMarkerTrivia2.ts:3:1]
|
||||||
2 │ foo() {
|
2 │ foo() {
|
||||||
3 │ <<<<<<< B
|
3 │ <<<<<<< B
|
||||||
· ──
|
· ──
|
||||||
4 │ a();
|
4 │ a();
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
|
@ -5396,10 +5402,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
× Unexpected token
|
× Unexpected token
|
||||||
╭─[compiler/conflictMarkerTrivia4.ts:2:2]
|
╭─[compiler/conflictMarkerTrivia4.ts:2:1]
|
||||||
1 │ const x = <div>
|
1 │ const x = <div>
|
||||||
2 │ <<<<<<< HEAD
|
2 │ <<<<<<< HEAD
|
||||||
· ──
|
· ──
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
× Identifier `y` has already been declared
|
× Identifier `y` has already been declared
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue