oxc/crates/oxc_parser/src/ts/statement.rs

562 lines
20 KiB
Rust

use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_diagnostics::Result;
use oxc_span::Span;
use super::{
list::{TSEnumMemberList, TSInterfaceOrObjectBodyList},
types::ModifierFlags,
};
use crate::{
js::{
declaration::{VariableDeclarationContext, VariableDeclarationParent},
function::FunctionKind,
},
lexer::Kind,
list::{NormalList, SeparatedList},
Parser, StatementContext,
};
impl<'a> Parser<'a> {
/** ------------------- Enum ------------------ */
pub(crate) fn is_at_enum_declaration(&mut self) -> bool {
self.at(Kind::Enum) || (self.at(Kind::Const) && self.peek_at(Kind::Enum))
}
/// `https://www.typescriptlang.org/docs/handbook/enums.html`
pub(crate) fn parse_ts_enum_declaration(
&mut self,
span: Span,
modifiers: Modifiers<'a>,
) -> Result<Declaration<'a>> {
self.expect(Kind::Enum)?;
let id = self.parse_binding_identifier()?;
let members = TSEnumMemberList::parse(self)?.members;
Ok(self.ast.ts_enum_declaration(span, id, members, modifiers))
}
pub(crate) fn parse_ts_enum_member(&mut self) -> Result<TSEnumMember<'a>> {
let span = self.start_span();
let id = self.parse_ts_enum_member_name()?;
let initializer =
if self.eat(Kind::Eq) { Some(self.parse_assignment_expression_base()?) } else { None };
Ok(TSEnumMember { span: self.end_span(span), id, initializer })
}
fn parse_ts_enum_member_name(&mut self) -> Result<TSEnumMemberName<'a>> {
match self.cur_kind() {
Kind::LBrack => {
Ok(TSEnumMemberName::ComputedPropertyName(self.parse_computed_property_name()?))
}
Kind::Str => Ok(TSEnumMemberName::StringLiteral(self.parse_literal_string()?)),
kind if kind.is_number() => {
Ok(TSEnumMemberName::NumberLiteral(self.parse_literal_number()?))
}
_ => Ok(TSEnumMemberName::Identifier(self.parse_identifier_name()?)),
}
}
/** ------------------- Annotation ----------------- */
pub(crate) fn parse_ts_type_annotation(
&mut self,
) -> Result<Option<Box<'a, TSTypeAnnotation<'a>>>> {
if self.at(Kind::Colon) {
let span = self.start_span();
self.bump_any(); // bump ':'
let type_annotation = self.parse_ts_type()?;
Ok(Some(self.ast.ts_type_annotation(self.end_span(span), type_annotation)))
} else {
Ok(None)
}
}
pub(crate) fn parse_ts_variable_annotation(
&mut self,
) -> Result<(Option<Box<'a, TSTypeAnnotation<'a>>>, bool)> {
if !self.at(Kind::Bang) {
return Ok((self.parse_ts_type_annotation()?, false));
}
if self.cur_token().is_on_new_line {
return Ok((None, false));
}
let span = self.start_span();
self.bump(Kind::Bang);
if self.eat(Kind::Colon) {
let type_annotation = self.parse_ts_type()?;
Ok((Some(self.ast.ts_type_annotation(self.end_span(span), type_annotation)), true))
} else {
Err(self.unexpected())
}
}
pub(crate) fn parse_ts_type_alias_declaration(
&mut self,
span: Span,
modifiers: Modifiers<'a>,
) -> Result<Declaration<'a>> {
self.expect(Kind::Type)?;
let id = self.parse_binding_identifier()?;
let params = self.parse_ts_type_parameters()?;
self.expect(Kind::Eq)?;
let annotation = self.parse_ts_type()?;
self.asi()?;
Ok(self.ast.ts_type_alias_declaration(span, id, annotation, params, modifiers))
}
/** --------------------- Interface ------------------------ */
pub(crate) fn parse_ts_interface_declaration(
&mut self,
span: Span,
modifiers: Modifiers<'a>,
) -> Result<Declaration<'a>> {
self.expect(Kind::Interface)?; // bump interface
let id = self.parse_binding_identifier()?;
let type_parameters = self.parse_ts_type_parameters()?;
let (extends, _) = self.parse_heritage_clause()?;
let body = self.parse_ts_interface_body()?;
let extends = extends.map(|e| self.ast.ts_interface_heritages(e));
Ok(self.ast.ts_interface_declaration(
self.end_span(span),
id,
body,
type_parameters,
extends,
modifiers,
))
}
fn parse_ts_interface_body(&mut self) -> Result<Box<'a, TSInterfaceBody<'a>>> {
let span = self.start_span();
let mut body_list = TSInterfaceOrObjectBodyList::new(self);
body_list.parse(self)?;
Ok(self.ast.ts_interface_body(self.end_span(span), body_list.body))
}
pub(crate) fn is_at_interface_declaration(&mut self) -> bool {
if !self.at(Kind::Interface) || self.peek_token().is_on_new_line {
false
} else {
self.peek_token().kind.is_binding_identifier() || self.peek_at(Kind::LCurly)
}
}
pub(crate) fn parse_ts_type_signature(&mut self) -> Result<TSSignature<'a>> {
if self.is_at_ts_index_signature_member() {
return self.parse_ts_index_signature_member();
}
match self.cur_kind() {
Kind::LParen | Kind::LAngle => self.parse_ts_call_signature_member(),
Kind::New if self.peek_at(Kind::LParen) || self.peek_at(Kind::LAngle) => {
self.parse_ts_constructor_signature_member()
}
Kind::Get if self.is_next_at_type_member_name() => {
self.parse_ts_getter_signature_member()
}
Kind::Set if self.is_next_at_type_member_name() => {
self.parse_ts_setter_signature_member()
}
_ => self.parse_ts_property_or_method_signature_member(),
}
}
/// Must be at `[ident:` or `<modifiers> [ident:`
pub(crate) fn is_at_ts_index_signature_member(&mut self) -> bool {
let mut offset = 0;
while self.is_nth_at_modifier(offset, false) {
offset += 1;
}
if !self.nth_at(offset, Kind::LBrack) {
return false;
}
if !self.nth_kind(offset + 1).is_identifier() {
return false;
}
self.nth_at(offset + 2, Kind::Colon)
}
pub(crate) fn is_nth_at_modifier(&mut self, n: u8, is_constructor_parameter: bool) -> bool {
let nth = self.nth(n);
if !(matches!(
nth.kind,
Kind::Public
| Kind::Protected
| Kind::Private
| Kind::Static
| Kind::Abstract
| Kind::Readonly
| Kind::Declare
| Kind::Override
)) {
return false;
}
let next = self.nth(n + 1);
if next.is_on_new_line {
false
} else {
let followed_by_any_member =
matches!(next.kind, Kind::PrivateIdentifier | Kind::LBrack)
|| next.kind.is_literal_property_name();
let followed_by_class_member = !is_constructor_parameter && next.kind == Kind::Star;
// allow `...` for error recovery
let followed_by_parameter = is_constructor_parameter
&& matches!(next.kind, Kind::LCurly | Kind::LBrack | Kind::Dot3);
followed_by_any_member || followed_by_class_member || followed_by_parameter
}
}
/** ----------------------- Namespace & Module ----------------------- */
fn parse_ts_module_block(&mut self) -> Result<Box<'a, TSModuleBlock<'a>>> {
let span = self.start_span();
let mut statements = self.ast.new_vec();
if self.at(Kind::LCurly) {
self.expect(Kind::LCurly)?;
while !self.eat(Kind::RCurly) && !self.at(Kind::Eof) {
let stmt = self.parse_ts_module_item()?;
statements.push(stmt);
}
}
Ok(self.ast.ts_module_block(self.end_span(span), statements))
}
fn parse_ts_module_item(&mut self) -> Result<Statement<'a>> {
self.parse_statement_list_item(StatementContext::StatementList)
}
pub(crate) fn parse_ts_namespace_or_module_declaration_body(
&mut self,
span: Span,
modifiers: Modifiers<'a>,
) -> Result<Box<'a, TSModuleDeclaration<'a>>> {
let id = match self.cur_kind() {
Kind::Str => self.parse_literal_string().map(TSModuleDeclarationName::StringLiteral),
_ => self.parse_identifier_name().map(TSModuleDeclarationName::Identifier),
}?;
let body = if self.eat(Kind::Dot) {
let span = self.start_span();
let decl =
self.parse_ts_namespace_or_module_declaration_body(span, Modifiers::empty())?;
TSModuleDeclarationBody::TSModuleDeclaration(decl)
} else {
let block = self.parse_ts_module_block()?;
self.asi()?;
TSModuleDeclarationBody::TSModuleBlock(block)
};
Ok(self.ast.ts_module_declaration(self.end_span(span), id, body, modifiers))
}
pub(crate) fn parse_ts_namespace_or_module_declaration(
&mut self,
modifiers: Modifiers<'a>,
) -> Result<Box<'a, TSModuleDeclaration<'a>>> {
let span = self.start_span();
self.expect(Kind::Namespace).or_else(|_| self.expect(Kind::Module))?;
self.parse_ts_namespace_or_module_declaration_body(span, modifiers)
}
pub(crate) fn parse_ts_global_declaration(
&mut self,
start_span: Span,
modifiers: Modifiers<'a>,
) -> Result<Box<'a, TSModuleDeclaration<'a>>> {
self.parse_ts_namespace_or_module_declaration_body(start_span, modifiers)
}
/** ----------------------- declare --------------------- */
pub(crate) fn parse_ts_declaration_statement(
&mut self,
start_span: Span,
) -> Result<Statement<'a>> {
let reserved_ctx = self.ctx;
let (flags, modifiers) = self.eat_modifiers_before_declaration();
let declare = flags.declare();
let r#async = flags.r#async();
self.ctx = self.ctx.and_ambient(declare).and_await(r#async);
let result = self.parse_declaration(start_span, modifiers);
self.ctx = reserved_ctx;
result.map(Statement::Declaration)
}
pub(crate) fn parse_declaration(
&mut self,
start_span: Span,
modifiers: Modifiers<'a>,
) -> Result<Declaration<'a>> {
match self.cur_kind() {
Kind::Namespace | Kind::Module => self
.parse_ts_namespace_or_module_declaration(modifiers)
.map(Declaration::TSModuleDeclaration),
Kind::Global => {
let decl = if self.peek_at(Kind::LCurly) {
// valid syntax for
// declare global { }
self.parse_ts_namespace_or_module_declaration_body(start_span, modifiers)
} else {
self.parse_ts_global_declaration(start_span, modifiers)
}?;
Ok(Declaration::TSModuleDeclaration(decl))
}
Kind::Type => self.parse_ts_type_alias_declaration(start_span, modifiers),
Kind::Enum => self.parse_ts_enum_declaration(start_span, modifiers),
Kind::Interface if self.is_at_interface_declaration() => {
self.parse_ts_interface_declaration(start_span, modifiers)
}
Kind::Class => self
.parse_class_declaration(start_span, modifiers)
.map(Declaration::ClassDeclaration),
Kind::Import => {
self.bump_any();
self.parse_ts_import_equals_declaration(start_span, true)
}
kind if kind.is_variable_declaration() => self
.parse_variable_declaration(
start_span,
VariableDeclarationContext::new(VariableDeclarationParent::Clause),
modifiers,
)
.map(Declaration::VariableDeclaration),
_ if self.at_function_with_async() => {
let declare = modifiers.contains(ModifierKind::Declare);
if declare {
self.parse_ts_declare_function(start_span, modifiers)
.map(Declaration::FunctionDeclaration)
} else if self.ts_enabled() {
self.parse_ts_function_impl(
start_span,
FunctionKind::Declaration { single_statement: true },
modifiers,
)
.map(Declaration::FunctionDeclaration)
} else {
self.parse_function_impl(FunctionKind::Declaration { single_statement: true })
.map(Declaration::FunctionDeclaration)
}
}
_ => Err(self.unexpected()),
}
}
pub(crate) fn parse_ts_declare_function(
&mut self,
start_span: Span,
modifiers: Modifiers<'a>,
) -> Result<Box<'a, Function<'a>>> {
let r#async = modifiers.contains(ModifierKind::Async);
self.expect(Kind::Function)?;
let func_kind = FunctionKind::TSDeclaration;
let id = self.parse_function_id(func_kind, r#async, false);
self.parse_function(start_span, id, r#async, false, func_kind, modifiers)
}
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)?;
let lhs_span = self.start_span();
let expression = self.parse_unary_expression_base(lhs_span)?;
Ok(self.ast.ts_type_assertion(self.end_span(span), type_annotation, expression))
}
pub(crate) fn parse_ts_import_equals_declaration(
&mut self,
span: Span,
is_export: bool,
) -> Result<Declaration<'a>> {
let import_kind = if !self.peek_at(Kind::Eq) && self.eat(Kind::Type) {
ImportOrExportKind::Value
} else {
ImportOrExportKind::Type
};
let id = self.parse_binding_identifier()?;
self.expect(Kind::Eq)?;
let reference_span = self.start_span();
let module_reference = if self.eat(Kind::Require) {
self.expect(Kind::LParen)?;
let expression = self.parse_literal_string()?;
self.expect(Kind::RParen)?;
TSModuleReference::ExternalModuleReference(TSExternalModuleReference {
span: self.end_span(reference_span),
expression,
})
} else {
TSModuleReference::TypeName(self.parse_ts_qualified_name()?)
};
self.asi()?;
Ok(self.ast.ts_import_equals_declaration(
self.end_span(span),
id,
module_reference,
is_export,
import_kind,
))
}
pub(crate) fn parse_ts_this_parameter(&mut self) -> Result<FormalParameter<'a>> {
let span = self.start_span();
let (ident_span, name) = self.parse_identifier_kind(Kind::This);
let type_annotation = self.parse_ts_type_annotation()?;
let kind = self.ast.binding_identifier(BindingIdentifier { span: ident_span, name });
let binding = self.ast.binding_pattern(kind, type_annotation, /* optional */ false);
Ok(self.ast.formal_parameter(
self.end_span(span),
binding,
/* accessibility */ None,
/* readonly */ false,
/* decorators */ self.ast.new_vec(),
))
}
pub(crate) fn eat_decorators(&mut self) -> Result<()> {
if !self.at(Kind::At) {
return Ok(());
}
let mut decorators = self.ast.new_vec();
while self.at(Kind::At) {
let decorator = self.parse_decorator()?;
decorators.push(decorator);
}
self.state.decorators = decorators;
Ok(())
}
pub(crate) fn eat_modifiers_before_declaration(&mut self) -> (ModifierFlags, Modifiers<'a>) {
let mut flags = ModifierFlags::empty();
let mut modifiers = self.ast.new_vec();
while self.at_modifier() {
let span = self.start_span();
let modifier_flag = self.cur_kind().into();
flags.set(modifier_flag, true);
let kind = self.cur_kind();
self.bump_any();
modifiers.push(Self::modifier(kind, self.end_span(span)));
}
(flags, Modifiers::new(modifiers))
}
fn at_modifier(&mut self) -> bool {
self.lookahead(Self::at_modifier_worker)
}
fn at_modifier_worker(&mut self) -> bool {
if !self.cur_kind().is_modifier_kind() {
return false;
}
match self.cur_kind() {
Kind::Const => !self.peek_token().is_on_new_line && self.peek_kind() == Kind::Enum,
Kind::Export => {
self.bump_any();
match self.cur_kind() {
Kind::Default => {
self.bump_any();
self.can_follow_default()
}
Kind::Type => {
self.bump_any();
self.can_follow_export()
}
_ => self.can_follow_export(),
}
}
Kind::Default => {
self.bump_any();
self.can_follow_default()
}
Kind::Accessor | Kind::Static | Kind::Get | Kind::Set => {
// These modifiers can cross line.
self.bump_any();
Self::can_follow_modifier(self.cur_kind())
}
// Rest modifiers cannot cross line
_ => {
self.bump_any();
Self::can_follow_modifier(self.cur_kind()) && !self.cur_token().is_on_new_line
}
}
}
fn can_follow_default(&mut self) -> bool {
let at_declaration =
matches!(self.cur_kind(), Kind::Class | Kind::Function | Kind::Interface);
let at_abstract_declaration = self.at(Kind::Abstract)
&& self.peek_at(Kind::Class)
&& !self.peek_token().is_on_new_line;
let at_async_function = self.at(Kind::Async)
&& self.peek_at(Kind::Function)
&& !self.peek_token().is_on_new_line;
at_declaration | at_abstract_declaration | at_async_function
}
fn can_follow_export(&mut self) -> bool {
// Note that the `export` in export assignment is not a modifier
// and are handled explicitly in the parser.
!matches!(self.cur_kind(), Kind::Star | Kind::As | Kind::LCurly)
&& Self::can_follow_modifier(self.cur_kind())
}
fn can_follow_modifier(kind: Kind) -> bool {
kind.is_literal_property_name()
|| matches!(kind, Kind::LCurly | Kind::LBrack | Kind::Star | Kind::Dot3)
}
fn modifier(kind: Kind, span: Span) -> Modifier {
let modifier_kind = match kind {
Kind::Abstract => ModifierKind::Abstract,
Kind::Declare => ModifierKind::Declare,
Kind::Private => ModifierKind::Private,
Kind::Protected => ModifierKind::Protected,
Kind::Public => ModifierKind::Public,
Kind::Static => ModifierKind::Static,
Kind::Readonly => ModifierKind::Readonly,
Kind::Override => ModifierKind::Override,
Kind::Async => ModifierKind::Async,
Kind::Const => ModifierKind::Const,
Kind::In => ModifierKind::In,
Kind::Out => ModifierKind::Out,
Kind::Export => ModifierKind::Export,
Kind::Default => ModifierKind::Default,
Kind::Accessor => ModifierKind::Accessor,
_ => unreachable!(),
};
Modifier { span, kind: modifier_kind }
}
}