mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
551 lines
21 KiB
Rust
551 lines
21 KiB
Rust
use oxc_allocator::{Box, Vec};
|
|
use oxc_ast::ast::*;
|
|
use oxc_diagnostics::Result;
|
|
use oxc_span::{Atom, Span};
|
|
|
|
use super::{
|
|
declaration::{VariableDeclarationContext, VariableDeclarationParent},
|
|
grammar::CoverGrammar,
|
|
list::SwitchCases,
|
|
};
|
|
use crate::{diagnostics, lexer::Kind, list::NormalList, Context, ParserImpl, StatementContext};
|
|
|
|
impl<'a> ParserImpl<'a> {
|
|
// Section 12
|
|
// The InputElementHashbangOrRegExp goal is used at the start of a Script
|
|
// or Module.
|
|
pub(crate) fn parse_hashbang(&mut self) -> Option<Hashbang<'a>> {
|
|
if self.cur_kind() == Kind::HashbangComment {
|
|
let span = self.start_span();
|
|
self.bump_any();
|
|
let span = self.end_span(span);
|
|
let src = &self.source_text[span.start as usize + 2..span.end as usize];
|
|
Some(self.ast.hashbang(span, Atom::from(src)))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// <https://tc39.es/ecma262/#prod-StatementList>
|
|
/// `StatementList`[Yield, Await, Return] :
|
|
/// `StatementListItem`[?Yield, ?Await, ?Return]
|
|
/// `StatementList`[?Yield, ?Await, ?Return] `StatementListItem`[?Yield, ?Await, ?Return]
|
|
pub(crate) fn parse_directives_and_statements(
|
|
&mut self,
|
|
is_top_level: bool,
|
|
) -> Result<(Vec<'a, Directive<'a>>, Vec<'a, Statement<'a>>)> {
|
|
let mut directives = self.ast.new_vec();
|
|
let mut statements = self.ast.new_vec();
|
|
|
|
let mut expecting_directives = true;
|
|
while !self.at(Kind::Eof) {
|
|
match self.cur_kind() {
|
|
Kind::RCurly if !is_top_level => break,
|
|
Kind::Import if !matches!(self.peek_kind(), Kind::Dot | Kind::LParen) => {
|
|
let stmt = self.parse_import_declaration()?;
|
|
statements.push(stmt);
|
|
expecting_directives = false;
|
|
}
|
|
Kind::Export => {
|
|
let stmt = self.parse_export_declaration()?;
|
|
statements.push(stmt);
|
|
expecting_directives = false;
|
|
}
|
|
Kind::At => {
|
|
self.eat_decorators()?;
|
|
expecting_directives = false;
|
|
continue;
|
|
}
|
|
_ => {
|
|
let stmt = self.parse_statement_list_item(StatementContext::StatementList)?;
|
|
|
|
// Section 11.2.1 Directive Prologue
|
|
// The only way to get a correct directive is to parse the statement first and check if it is a string literal.
|
|
// All other method are flawed, see test cases in [babel](https://github.com/babel/babel/blob/main/packages/babel-parser/test/fixtures/core/categorized/not-directive/input.js)
|
|
if expecting_directives {
|
|
if let Statement::ExpressionStatement(expr) = &stmt {
|
|
if let Expression::StringLiteral(string) = &expr.expression {
|
|
// span start will mismatch if they are parenthesized when `preserve_parens = false`
|
|
if expr.span.start == string.span.start {
|
|
let src = &self.source_text[string.span.start as usize + 1
|
|
..string.span.end as usize - 1];
|
|
let directive = self.ast.directive(
|
|
expr.span,
|
|
(*string).clone(),
|
|
Atom::from(src),
|
|
);
|
|
directives.push(directive);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
expecting_directives = false;
|
|
}
|
|
|
|
statements.push(stmt);
|
|
}
|
|
};
|
|
}
|
|
|
|
Ok((directives, statements))
|
|
}
|
|
|
|
/// `StatementListItem`[Yield, Await, Return] :
|
|
/// Statement[?Yield, ?Await, ?Return]
|
|
/// Declaration[?Yield, ?Await]
|
|
pub(crate) fn parse_statement_list_item(
|
|
&mut self,
|
|
stmt_ctx: StatementContext,
|
|
) -> Result<Statement<'a>> {
|
|
let start_span = self.start_span();
|
|
|
|
if self.at(Kind::At) {
|
|
self.eat_decorators()?;
|
|
}
|
|
|
|
match self.cur_kind() {
|
|
Kind::LCurly => self.parse_block_statement(),
|
|
Kind::Semicolon => Ok(self.parse_empty_statement()),
|
|
Kind::If => self.parse_if_statement(),
|
|
Kind::Do => self.parse_do_while_statement(),
|
|
Kind::While => self.parse_while_statement(),
|
|
Kind::For => self.parse_for_statement(),
|
|
Kind::Break | Kind::Continue => self.parse_break_or_continue_statement(),
|
|
Kind::With => self.parse_with_statement(),
|
|
Kind::Switch => self.parse_switch_statement(),
|
|
Kind::Throw => self.parse_throw_statement(),
|
|
Kind::Try => self.parse_try_statement(),
|
|
Kind::Debugger => self.parse_debugger_statement(),
|
|
Kind::Class => self.parse_class_statement(stmt_ctx, start_span),
|
|
Kind::Import if !matches!(self.peek_kind(), Kind::Dot | Kind::LParen) => {
|
|
self.parse_import_declaration()
|
|
}
|
|
Kind::Export => self.parse_export_declaration(),
|
|
// [+Return] ReturnStatement[?Yield, ?Await]
|
|
Kind::Return => self.parse_return_statement(),
|
|
Kind::Var => self.parse_variable_statement(stmt_ctx),
|
|
Kind::Const if !(self.ts_enabled() && self.is_at_enum_declaration()) => {
|
|
self.parse_variable_statement(stmt_ctx)
|
|
}
|
|
Kind::Let if !self.cur_token().escaped() => self.parse_let(stmt_ctx),
|
|
Kind::Await
|
|
if self.peek_kind() == Kind::Using && self.nth_kind(2).is_binding_identifier() =>
|
|
{
|
|
self.parse_using()
|
|
}
|
|
Kind::Using if self.peek_kind().is_binding_identifier() => self.parse_using(),
|
|
_ if self.at_function_with_async() => self.parse_function_declaration(stmt_ctx),
|
|
_ if self.ts_enabled() && self.at_start_of_ts_declaration() => {
|
|
self.parse_ts_declaration_statement(start_span)
|
|
}
|
|
_ => self.parse_expression_or_labeled_statement(),
|
|
}
|
|
}
|
|
|
|
fn parse_expression_or_labeled_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
let expr = self.parse_expression()?;
|
|
if let Expression::Identifier(ident) = &expr {
|
|
// Section 14.13 Labelled Statement
|
|
// Avoids lookahead for a labeled statement, which is on a hot path
|
|
if self.eat(Kind::Colon) {
|
|
let label = LabelIdentifier { span: ident.span, name: ident.name.clone() };
|
|
let body = self.parse_statement_list_item(StatementContext::Label)?;
|
|
return Ok(self.ast.labeled_statement(self.end_span(span), label, body));
|
|
}
|
|
}
|
|
self.parse_expression_statement(span, expr)
|
|
}
|
|
|
|
/// Section 14.2 Block Statement
|
|
pub(crate) fn parse_block(&mut self) -> Result<Box<'a, BlockStatement<'a>>> {
|
|
let span = self.start_span();
|
|
self.expect(Kind::LCurly)?;
|
|
let mut body = self.ast.new_vec();
|
|
while !self.at(Kind::RCurly) && !self.at(Kind::Eof) {
|
|
let stmt = self.parse_statement_list_item(StatementContext::StatementList)?;
|
|
body.push(stmt);
|
|
}
|
|
self.expect(Kind::RCurly)?;
|
|
Ok(self.ast.block(self.end_span(span), body))
|
|
}
|
|
|
|
pub(crate) fn parse_block_statement(&mut self) -> Result<Statement<'a>> {
|
|
let block = self.parse_block()?;
|
|
Ok(self.ast.block_statement(block))
|
|
}
|
|
|
|
/// Section 14.3.2 Variable Statement
|
|
pub(crate) fn parse_variable_statement(
|
|
&mut self,
|
|
stmt_ctx: StatementContext,
|
|
) -> Result<Statement<'a>> {
|
|
let start_span = self.start_span();
|
|
let decl = self.parse_variable_declaration(
|
|
start_span,
|
|
VariableDeclarationContext::new(VariableDeclarationParent::Statement),
|
|
Modifiers::empty(),
|
|
)?;
|
|
|
|
if stmt_ctx.is_single_statement() && decl.kind.is_lexical() {
|
|
self.error(diagnostics::LexicalDeclarationSingleStatement(decl.span));
|
|
}
|
|
|
|
Ok(Statement::Declaration(Declaration::VariableDeclaration(decl)))
|
|
}
|
|
|
|
/// Section 14.4 Empty Statement
|
|
fn parse_empty_statement(&mut self) -> Statement<'a> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `;`
|
|
self.ast.empty_statement(self.end_span(span))
|
|
}
|
|
|
|
/// Section 14.5 Expression Statement
|
|
pub(crate) fn parse_expression_statement(
|
|
&mut self,
|
|
span: Span,
|
|
expression: Expression<'a>,
|
|
) -> Result<Statement<'a>> {
|
|
self.asi()?;
|
|
Ok(self.ast.expression_statement(self.end_span(span), expression))
|
|
}
|
|
|
|
/// Section 14.6 If Statement
|
|
fn parse_if_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `if`
|
|
let test = self.parse_paren_expression()?;
|
|
let consequent = self.parse_statement_list_item(StatementContext::If)?;
|
|
let alternate = self
|
|
.eat(Kind::Else)
|
|
.then(|| self.parse_statement_list_item(StatementContext::If))
|
|
.transpose()?;
|
|
Ok(self.ast.if_statement(self.end_span(span), test, consequent, alternate))
|
|
}
|
|
|
|
/// Section 14.7.2 Do-While Statement
|
|
fn parse_do_while_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `do`
|
|
let body = self.parse_statement_list_item(StatementContext::Do)?;
|
|
self.expect(Kind::While)?;
|
|
let test = self.parse_paren_expression()?;
|
|
self.bump(Kind::Semicolon);
|
|
Ok(self.ast.do_while_statement(self.end_span(span), body, test))
|
|
}
|
|
|
|
/// Section 14.7.3 While Statement
|
|
fn parse_while_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `while`
|
|
let test = self.parse_paren_expression()?;
|
|
let body = self.parse_statement_list_item(StatementContext::While)?;
|
|
Ok(self.ast.while_statement(self.end_span(span), test, body))
|
|
}
|
|
|
|
/// Section 14.7.4 For Statement
|
|
fn parse_for_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `for`
|
|
|
|
// [+Await]
|
|
let r#await = self.ctx.has_await() && self.eat(Kind::Await);
|
|
|
|
self.expect(Kind::LParen)?;
|
|
|
|
// for (;..
|
|
if self.at(Kind::Semicolon) {
|
|
return self.parse_for_loop(span, None, r#await);
|
|
}
|
|
|
|
// for (let | for (const | for (var
|
|
// disallow for (let in ..)
|
|
if self.at(Kind::Const)
|
|
|| self.at(Kind::Var)
|
|
|| (self.at(Kind::Let) && self.peek_kind().is_after_let())
|
|
{
|
|
return self.parse_variable_declaration_for_statement(span, r#await);
|
|
}
|
|
|
|
if (self.cur_kind() == Kind::Await && self.peek_kind() == Kind::Using)
|
|
|| (self.cur_kind() == Kind::Using && self.peek_kind() == Kind::Ident)
|
|
{
|
|
return self.parse_using_declaration_for_statement(span, r#await);
|
|
}
|
|
|
|
let is_let_of = self.at(Kind::Let) && self.peek_at(Kind::Of);
|
|
let is_async_of =
|
|
self.at(Kind::Async) && !self.cur_token().escaped() && self.peek_at(Kind::Of);
|
|
let expr_span = self.start_span();
|
|
|
|
if self.at(Kind::RParen) {
|
|
return self.parse_for_loop(span, None, r#await);
|
|
}
|
|
|
|
let init_expression = self.without_context(Context::In, ParserImpl::parse_expression)?;
|
|
|
|
// for (a.b in ...), for ([a] in ..), for ({a} in ..)
|
|
if self.at(Kind::In) || self.at(Kind::Of) {
|
|
let target = AssignmentTarget::cover(init_expression, self)
|
|
.map_err(|_| diagnostics::UnexpectedToken(self.end_span(expr_span)))?;
|
|
let for_stmt_left = ForStatementLeft::AssignmentTarget(target);
|
|
if !r#await && is_async_of {
|
|
self.error(diagnostics::ForLoopAsyncOf(self.end_span(expr_span)));
|
|
}
|
|
if is_let_of {
|
|
self.error(diagnostics::UnexpectedToken(self.end_span(expr_span)));
|
|
}
|
|
return self.parse_for_in_or_of_loop(span, r#await, for_stmt_left);
|
|
}
|
|
|
|
self.parse_for_loop(span, Some(ForStatementInit::Expression(init_expression)), r#await)
|
|
}
|
|
|
|
fn parse_variable_declaration_for_statement(
|
|
&mut self,
|
|
span: Span,
|
|
r#await: bool,
|
|
) -> Result<Statement<'a>> {
|
|
let start_span = self.start_span();
|
|
let init_declaration = self.without_context(Context::In, |p| {
|
|
let decl_ctx = VariableDeclarationContext::new(VariableDeclarationParent::For);
|
|
p.parse_variable_declaration(start_span, decl_ctx, Modifiers::empty())
|
|
})?;
|
|
|
|
// for (.. a in) for (.. a of)
|
|
if matches!(self.cur_kind(), Kind::In | Kind::Of) {
|
|
let init = ForStatementLeft::VariableDeclaration(init_declaration);
|
|
return self.parse_for_in_or_of_loop(span, r#await, init);
|
|
}
|
|
|
|
let init = Some(ForStatementInit::VariableDeclaration(init_declaration));
|
|
self.parse_for_loop(span, init, r#await)
|
|
}
|
|
|
|
fn parse_using_declaration_for_statement(
|
|
&mut self,
|
|
span: Span,
|
|
r#await: bool,
|
|
) -> Result<Statement<'a>> {
|
|
let using_decl = self.parse_using_declaration(StatementContext::For)?;
|
|
|
|
if matches!(self.cur_kind(), Kind::In) {
|
|
if using_decl.is_await {
|
|
self.error(diagnostics::AwaitUsingDeclarationNotAllowedInForInStatement(
|
|
using_decl.span,
|
|
));
|
|
} else {
|
|
self.error(diagnostics::UsingDeclarationNotAllowedInForInStatement(
|
|
using_decl.span,
|
|
));
|
|
}
|
|
}
|
|
|
|
if matches!(self.cur_kind(), Kind::In | Kind::Of) {
|
|
let init = ForStatementLeft::UsingDeclaration(self.ast.alloc(using_decl));
|
|
return self.parse_for_in_or_of_loop(span, r#await, init);
|
|
}
|
|
|
|
let init = Some(ForStatementInit::UsingDeclaration(self.ast.alloc(using_decl)));
|
|
self.parse_for_loop(span, init, r#await)
|
|
}
|
|
|
|
fn parse_for_loop(
|
|
&mut self,
|
|
span: Span,
|
|
init: Option<ForStatementInit<'a>>,
|
|
r#await: bool,
|
|
) -> Result<Statement<'a>> {
|
|
self.expect(Kind::Semicolon)?;
|
|
let test = if !self.at(Kind::Semicolon) && !self.at(Kind::RParen) {
|
|
Some(self.with_context(Context::In, ParserImpl::parse_expression)?)
|
|
} else {
|
|
None
|
|
};
|
|
self.expect(Kind::Semicolon)?;
|
|
let update = if self.at(Kind::RParen) {
|
|
None
|
|
} else {
|
|
Some(self.with_context(Context::In, ParserImpl::parse_expression)?)
|
|
};
|
|
self.expect(Kind::RParen)?;
|
|
if r#await {
|
|
self.error(diagnostics::ForAwait(self.end_span(span)));
|
|
}
|
|
let body = self.parse_statement_list_item(StatementContext::For)?;
|
|
Ok(self.ast.for_statement(self.end_span(span), init, test, update, body))
|
|
}
|
|
|
|
fn parse_for_in_or_of_loop(
|
|
&mut self,
|
|
span: Span,
|
|
r#await: bool,
|
|
left: ForStatementLeft<'a>,
|
|
) -> Result<Statement<'a>> {
|
|
let is_for_in = self.at(Kind::In);
|
|
self.bump_any(); // bump `in` or `of`
|
|
let right = if is_for_in {
|
|
self.parse_expression()
|
|
} else {
|
|
self.parse_assignment_expression_base()
|
|
}?;
|
|
self.expect(Kind::RParen)?;
|
|
|
|
if r#await && is_for_in {
|
|
self.error(diagnostics::ForAwait(self.end_span(span)));
|
|
}
|
|
|
|
let body = self.parse_statement_list_item(StatementContext::For)?;
|
|
let span = self.end_span(span);
|
|
|
|
if is_for_in {
|
|
Ok(self.ast.for_in_statement(span, left, right, body))
|
|
} else {
|
|
Ok(self.ast.for_of_statement(span, r#await, left, right, body))
|
|
}
|
|
}
|
|
|
|
/// Section 14.8 Continue Statement
|
|
/// Section 14.9 Break Statement
|
|
fn parse_break_or_continue_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
let kind = self.cur_kind();
|
|
self.bump_any(); // bump `break` or `continue`
|
|
let label =
|
|
if self.can_insert_semicolon() { None } else { Some(self.parse_label_identifier()?) };
|
|
self.asi()?;
|
|
let end_span = self.end_span(span);
|
|
match kind {
|
|
Kind::Break => Ok(self.ast.break_statement(end_span, label)),
|
|
Kind::Continue => Ok(self.ast.continue_statement(end_span, label)),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
/// Section 14.10 Return Statement
|
|
/// `ReturnStatement`[Yield, Await] :
|
|
/// return ;
|
|
/// return [no `LineTerminator` here] Expression[+In, ?Yield, ?Await] ;
|
|
fn parse_return_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `return`
|
|
let argument = if self.eat(Kind::Semicolon) || self.can_insert_semicolon() {
|
|
None
|
|
} else {
|
|
let expr = self.with_context(Context::In, ParserImpl::parse_expression)?;
|
|
self.asi()?;
|
|
Some(expr)
|
|
};
|
|
if !self.ctx.has_return() {
|
|
self.error(diagnostics::ReturnStatementOnlyInFunctionBody(Span::new(
|
|
span.start,
|
|
span.start + 6,
|
|
)));
|
|
}
|
|
Ok(self.ast.return_statement(self.end_span(span), argument))
|
|
}
|
|
|
|
/// Section 14.11 With Statement
|
|
fn parse_with_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `with`
|
|
let object = self.parse_paren_expression()?;
|
|
let body = self.parse_statement_list_item(StatementContext::With)?;
|
|
let span = self.end_span(span);
|
|
Ok(self.ast.with_statement(span, object, body))
|
|
}
|
|
|
|
/// Section 14.12 Switch Statement
|
|
fn parse_switch_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `switch`
|
|
let discriminant = self.parse_paren_expression()?;
|
|
let cases = {
|
|
let mut switch_cases = SwitchCases::new(self);
|
|
switch_cases.parse(self)?;
|
|
switch_cases.elements
|
|
};
|
|
Ok(self.ast.switch_statement(self.end_span(span), discriminant, cases))
|
|
}
|
|
|
|
pub(crate) fn parse_switch_case(&mut self) -> Result<SwitchCase<'a>> {
|
|
let span = self.start_span();
|
|
let test = match self.cur_kind() {
|
|
Kind::Default => {
|
|
self.bump_any();
|
|
None
|
|
}
|
|
Kind::Case => {
|
|
self.bump_any();
|
|
let expression = self.parse_expression()?;
|
|
Some(expression)
|
|
}
|
|
_ => return Err(self.unexpected()),
|
|
};
|
|
self.expect(Kind::Colon)?;
|
|
let mut consequent = self.ast.new_vec();
|
|
while !matches!(self.cur_kind(), Kind::Case | Kind::Default | Kind::RCurly | Kind::Eof) {
|
|
let stmt = self.parse_statement_list_item(StatementContext::StatementList)?;
|
|
consequent.push(stmt);
|
|
}
|
|
Ok(self.ast.switch_case(self.end_span(span), test, consequent))
|
|
}
|
|
|
|
/// Section 14.14 Throw Statement
|
|
fn parse_throw_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `throw`
|
|
if self.cur_token().is_on_new_line {
|
|
self.error(diagnostics::IllegalNewline(
|
|
"throw",
|
|
self.end_span(span),
|
|
self.cur_token().span(),
|
|
));
|
|
}
|
|
let argument = self.parse_expression()?;
|
|
self.asi()?;
|
|
Ok(self.ast.throw_statement(self.end_span(span), argument))
|
|
}
|
|
|
|
/// Section 14.15 Try Statement
|
|
fn parse_try_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // bump `try`
|
|
|
|
let block = self.parse_block()?;
|
|
|
|
let handler = self.at(Kind::Catch).then(|| self.parse_catch_clause()).transpose()?;
|
|
|
|
let finalizer = self.eat(Kind::Finally).then(|| self.parse_block()).transpose()?;
|
|
|
|
if handler.is_none() && finalizer.is_none() {
|
|
let range = Span::new(block.span.end, block.span.end);
|
|
self.error(diagnostics::ExpectCatchFinally(range));
|
|
}
|
|
|
|
Ok(self.ast.try_statement(self.end_span(span), block, handler, finalizer))
|
|
}
|
|
|
|
fn parse_catch_clause(&mut self) -> Result<Box<'a, CatchClause<'a>>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `catch`
|
|
let param = if self.eat(Kind::LParen) {
|
|
let pattern = self.parse_binding_pattern(false)?;
|
|
self.expect(Kind::RParen)?;
|
|
Some(pattern)
|
|
} else {
|
|
None
|
|
};
|
|
let body = self.parse_block()?;
|
|
Ok(self.ast.catch_clause(self.end_span(span), param, body))
|
|
}
|
|
|
|
/// Section 14.16 Debugger Statement
|
|
fn parse_debugger_statement(&mut self) -> Result<Statement<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any();
|
|
self.asi()?;
|
|
Ok(self.ast.debugger_statement(self.end_span(span)))
|
|
}
|
|
}
|