mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
refactor(parser): improve parsing of parse_function_or_constructor_type (#3892)
part of #3502
This commit is contained in:
parent
442aca3ba8
commit
187f0782c1
5 changed files with 96 additions and 120 deletions
|
|
@ -31,7 +31,7 @@ impl<'a> ParserImpl<'a> {
|
|||
Ok(self.ast.binding_pattern(self.end_span(span), kind, type_annotation, optional))
|
||||
}
|
||||
|
||||
pub(super) fn parse_binding_pattern_kind(&mut self) -> Result<BindingPatternKind<'a>> {
|
||||
pub(crate) fn parse_binding_pattern_kind(&mut self) -> Result<BindingPatternKind<'a>> {
|
||||
match self.cur_kind() {
|
||||
Kind::LCurly => self.parse_object_binding_pattern(),
|
||||
Kind::LBrack => self.parse_array_binding_pattern(),
|
||||
|
|
|
|||
|
|
@ -396,7 +396,6 @@ impl<'a> ParserImpl<'a> {
|
|||
|
||||
pub(crate) fn parse_ts_type_assertion(&mut self) -> Result<Expression<'a>> {
|
||||
let span = self.start_span();
|
||||
self.re_lex_ts_l_angle();
|
||||
self.expect(Kind::LAngle)?;
|
||||
let type_annotation = self.parse_ts_type()?;
|
||||
self.expect(Kind::RAngle)?;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use super::list::{
|
|||
};
|
||||
use crate::{
|
||||
diagnostics,
|
||||
js::list::{ArrayPatternList, ObjectPatternProperties},
|
||||
lexer::Kind,
|
||||
list::{NormalList, SeparatedList},
|
||||
modifiers::ModifierFlags,
|
||||
|
|
@ -19,20 +18,93 @@ use crate::{
|
|||
|
||||
impl<'a> ParserImpl<'a> {
|
||||
pub(crate) fn parse_ts_type(&mut self) -> Result<TSType<'a>> {
|
||||
if self.is_at_constructor_type() {
|
||||
return self.parse_ts_constructor_type();
|
||||
if self.is_start_of_function_type_or_constructor_type() {
|
||||
return self.parse_function_or_constructor_type();
|
||||
}
|
||||
|
||||
if self.is_at_function_type() {
|
||||
return self.parse_ts_function_type();
|
||||
}
|
||||
|
||||
let left_span = self.start_span();
|
||||
let left = self.parse_ts_union_type()?;
|
||||
|
||||
self.parse_ts_conditional_type(left_span, left)
|
||||
}
|
||||
|
||||
fn parse_function_or_constructor_type(&mut self) -> Result<TSType<'a>> {
|
||||
let span = self.start_span();
|
||||
let r#abstract = self.eat(Kind::Abstract);
|
||||
let is_constructor_type = self.eat(Kind::New);
|
||||
let type_parameters = self.parse_ts_type_parameters()?;
|
||||
let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?;
|
||||
self.expect(Kind::Arrow)?;
|
||||
let return_type = {
|
||||
let return_type_span = self.start_span();
|
||||
let return_type = self.parse_ts_return_type()?;
|
||||
self.ast.ts_type_annotation(self.end_span(return_type_span), return_type)
|
||||
};
|
||||
|
||||
let span = self.end_span(span);
|
||||
Ok(if is_constructor_type {
|
||||
if let Some(this_param) = &this_param {
|
||||
// type Foo = new (this: number) => any;
|
||||
self.error(diagnostics::ts_constructor_this_parameter(this_param.span));
|
||||
}
|
||||
self.ast.ts_constructor_type(span, r#abstract, params, return_type, type_parameters)
|
||||
} else {
|
||||
self.ast.ts_function_type(span, this_param, params, return_type, type_parameters)
|
||||
})
|
||||
}
|
||||
|
||||
fn is_start_of_function_type_or_constructor_type(&mut self) -> bool {
|
||||
if self.at(Kind::LAngle) {
|
||||
return true;
|
||||
}
|
||||
if self.at(Kind::LParen) && self.lookahead(Self::is_unambiguously_start_of_function_type) {
|
||||
return true;
|
||||
}
|
||||
self.at(Kind::New) || (self.at(Kind::Abstract) && self.peek_at(Kind::New))
|
||||
}
|
||||
|
||||
fn is_unambiguously_start_of_function_type(&mut self) -> bool {
|
||||
self.bump_any();
|
||||
// ( )
|
||||
// ( ...
|
||||
if matches!(self.cur_kind(), Kind::RParen | Kind::Dot3) {
|
||||
return true;
|
||||
}
|
||||
if self.skip_parameter_start() {
|
||||
// ( xxx :
|
||||
// ( xxx ,
|
||||
// ( xxx ?
|
||||
// ( xxx =
|
||||
if matches!(self.cur_kind(), Kind::Colon | Kind::Comma | Kind::Question | Kind::Eq) {
|
||||
return true;
|
||||
}
|
||||
// ( xxx ) =>
|
||||
if self.eat(Kind::RParen) && self.at(Kind::Arrow) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn skip_parameter_start(&mut self) -> bool {
|
||||
// Skip modifiers
|
||||
loop {
|
||||
if self.cur_kind().is_modifier_kind() && !self.peek_at(Kind::Comma) {
|
||||
self.bump_any();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if self.cur_kind().is_identifier() || self.at(Kind::This) {
|
||||
self.bump_any();
|
||||
return true;
|
||||
}
|
||||
if matches!(self.cur_kind(), Kind::LBrack | Kind::LCurly)
|
||||
&& self.parse_binding_pattern_kind().is_ok()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ts_type_parameters(
|
||||
&mut self,
|
||||
) -> Result<Option<Box<'a, TSTypeParameterDeclaration<'a>>>> {
|
||||
|
|
@ -162,10 +234,6 @@ impl<'a> ParserImpl<'a> {
|
|||
Ok(left)
|
||||
}
|
||||
|
||||
fn is_at_constructor_type(&mut self) -> bool {
|
||||
self.at(Kind::New) || (self.at(Kind::Abstract) && self.peek_at(Kind::New))
|
||||
}
|
||||
|
||||
// test ts ts_union_type
|
||||
// type A = string | number;
|
||||
// type B = | A | void | null;
|
||||
|
|
@ -474,51 +542,6 @@ impl<'a> ParserImpl<'a> {
|
|||
Ok(self.ast.ts_tuple_type(self.end_span(span), elements))
|
||||
}
|
||||
|
||||
fn is_at_function_type(&mut self) -> bool {
|
||||
if self.at(Kind::LAngle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.at(Kind::LParen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let checkpoint = self.checkpoint();
|
||||
|
||||
self.bump_any(); // bump (
|
||||
|
||||
if self.at(Kind::RParen) || self.at(Kind::Dot3) {
|
||||
self.rewind(checkpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut is_function_parameter_start =
|
||||
self.at(Kind::This) || self.cur_kind().is_binding_identifier();
|
||||
|
||||
if is_function_parameter_start {
|
||||
self.bump_any();
|
||||
}
|
||||
|
||||
if match self.cur_kind() {
|
||||
Kind::LBrack => ArrayPatternList::parse(self).is_ok(),
|
||||
Kind::LCurly => ObjectPatternProperties::parse(self).is_ok(),
|
||||
_ => false,
|
||||
} {
|
||||
is_function_parameter_start = true;
|
||||
}
|
||||
|
||||
let result = if is_function_parameter_start {
|
||||
matches!(self.cur_kind(), Kind::Colon | Kind::Eq | Kind::Comma | Kind::Question)
|
||||
|| (self.at(Kind::RParen) && self.peek_at(Kind::Arrow))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
self.rewind(checkpoint);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn is_at_mapped_type(&mut self) -> bool {
|
||||
if !self.at(Kind::LCurly) {
|
||||
return false;
|
||||
|
|
@ -731,49 +754,6 @@ impl<'a> ParserImpl<'a> {
|
|||
Ok(TSImportAttributes { span, elements })
|
||||
}
|
||||
|
||||
fn parse_ts_constructor_type(&mut self) -> Result<TSType<'a>> {
|
||||
let span = self.start_span();
|
||||
let r#abstract = self.eat(Kind::Abstract);
|
||||
self.expect(Kind::New)?;
|
||||
let type_parameters = self.parse_ts_type_parameters()?;
|
||||
let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?;
|
||||
|
||||
if let Some(this_param) = this_param {
|
||||
// type Foo = new (this: number) => any;
|
||||
self.error(diagnostics::ts_constructor_this_parameter(this_param.span));
|
||||
}
|
||||
|
||||
self.expect(Kind::Arrow)?;
|
||||
let return_type_span = self.start_span();
|
||||
let return_type = self.parse_ts_return_type()?;
|
||||
let return_type = self.ast.ts_type_annotation(self.end_span(return_type_span), return_type);
|
||||
|
||||
Ok(self.ast.ts_constructor_type(
|
||||
self.end_span(span),
|
||||
r#abstract,
|
||||
params,
|
||||
return_type,
|
||||
type_parameters,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_ts_function_type(&mut self) -> Result<TSType<'a>> {
|
||||
let span = self.start_span();
|
||||
let type_parameters = self.parse_ts_type_parameters()?;
|
||||
let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?;
|
||||
let return_type_span = self.start_span();
|
||||
self.expect(Kind::Arrow)?;
|
||||
let return_type = self.parse_ts_return_type()?;
|
||||
let return_type = self.ast.ts_type_annotation(self.end_span(return_type_span), return_type);
|
||||
Ok(self.ast.ts_function_type(
|
||||
self.end_span(span),
|
||||
this_param,
|
||||
params,
|
||||
return_type,
|
||||
type_parameters,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_ts_infer_type(&mut self) -> Result<TSType<'a>> {
|
||||
let span = self.start_span();
|
||||
self.expect(Kind::Infer)?;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ pub fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<
|
|||
check_duplicate_bound_names(params, ctx);
|
||||
}
|
||||
|
||||
let is_inside_constructor = ctx.current_scope_flags().is_constructor();
|
||||
let is_inside_constructor =
|
||||
!params.kind.is_signature() && ctx.current_scope_flags().is_constructor();
|
||||
let mut has_optional = false;
|
||||
|
||||
for item in ¶ms.items {
|
||||
|
|
|
|||
|
|
@ -3999,20 +3999,18 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
|||
2 │ }
|
||||
╰────
|
||||
|
||||
× Expected `)` but found `Identifier`
|
||||
╭─[compiler/ParameterList5.ts:1:23]
|
||||
× A parameter property is only allowed in a constructor implementation.
|
||||
╭─[compiler/ParameterList5.ts:1:16]
|
||||
1 │ function A(): (public B) => C {
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
· ────────
|
||||
2 │ }
|
||||
╰────
|
||||
|
||||
× Expected `)` but found `Identifier`
|
||||
╭─[compiler/ParameterList6.ts:2:26]
|
||||
× A parameter property is only allowed in a constructor implementation.
|
||||
╭─[compiler/ParameterList6.ts:2:19]
|
||||
1 │ class C {
|
||||
2 │ constructor(C: (public A) => any) {
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
· ────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
|
|
@ -17725,20 +17723,18 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
|
|||
2 │ }
|
||||
╰────
|
||||
|
||||
× Expected `)` but found `Identifier`
|
||||
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts:1:23]
|
||||
× A parameter property is only allowed in a constructor implementation.
|
||||
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts:1:16]
|
||||
1 │ function A(): (public B) => C {
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
· ────────
|
||||
2 │ }
|
||||
╰────
|
||||
|
||||
× Expected `)` but found `Identifier`
|
||||
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList6.ts:2:26]
|
||||
× A parameter property is only allowed in a constructor implementation.
|
||||
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList6.ts:2:19]
|
||||
1 │ class C {
|
||||
2 │ constructor(C: (public A) => any) {
|
||||
· ┬
|
||||
· ╰── `)` expected
|
||||
· ────────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue