mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
### Every structure has 2 builder methods:
1. `xxx` e.g. `block_statement`
```rust
#[inline]
pub fn block_statement(self, span: Span, body: Vec<'a, Statement<'a>>) -> BlockStatement<'a> {
BlockStatement { span, body, scope_id: Default::default() }
}
```
2. `alloc_xxx` e.g. `alloc_block_statement`
```rust
#[inline]
pub fn alloc_block_statement(
self,
span: Span,
body: Vec<'a, Statement<'a>>,
) -> Box<'a, BlockStatement<'a>> {
self.block_statement(span, body).into_in(self.allocator)
}
```
### We generate 3 types of methods for enums:
1. `yyy_xxx` e.g. `statement_block`
```rust
#[inline]
pub fn statement_block(self, span: Span, body: Vec<'a, Statement<'a>>) -> Statement<'a> {
Statement::BlockStatement(self.alloc(self.block_statement(span, body)))
}
```
2. `yyy_from_xxx` e.g. `statement_from_block`
```rust
#[inline]
pub fn statement_from_block<T>(self, inner: T) -> Statement<'a>
where
T: IntoIn<'a, Box<'a, BlockStatement<'a>>>,
{
Statement::BlockStatement(inner.into_in(self.allocator))
}
```
3. `yyy_xxx` where `xxx` is inherited e.g. `statement_declaration`
```rust
#[inline]
pub fn statement_declaration(self, inner: Declaration<'a>) -> Statement<'a> {
Statement::from(inner)
}
```
------------
### Generic parameters:
We no longer accept `Box<'a, ADT>`, `Atom` or `&'a str`, Instead we use `IntoIn<'a, Box<'a, ADT>>`, `IntoIn<'a, Atom<'a>>` and `IntoIn<'a, &'a str>` respectively.
It allows us to rewrite things like this:
```rust
let ident = IdentifierReference::new(SPAN, Atom::from("require"));
let number_literal_expr = self.ast.expression_numeric_literal(
right_expr.span(),
num,
raw,
self.ast.new_str(num.to_string().as_str()),
NumberBase::Decimal,
);
```
As this:
```rust
let ident = IdentifierReference::new(SPAN, "require");
let number_literal_expr = self.ast.expression_numeric_literal(
right_expr.span(),
num,
raw,
num.to_string(),
NumberBase::Decimal,
);
```
351 lines
12 KiB
Rust
351 lines
12 KiB
Rust
use std::cell::Cell;
|
|
|
|
use oxc_allocator::Box;
|
|
use oxc_ast::ast::*;
|
|
use oxc_diagnostics::Result;
|
|
use oxc_span::Span;
|
|
|
|
use super::FunctionKind;
|
|
use crate::{
|
|
diagnostics,
|
|
lexer::Kind,
|
|
modifiers::{ModifierFlags, ModifierKind, Modifiers},
|
|
Context, ParserImpl, StatementContext,
|
|
};
|
|
|
|
impl FunctionKind {
|
|
pub(crate) fn is_id_required(self) -> bool {
|
|
matches!(self, Self::Declaration)
|
|
}
|
|
|
|
pub(crate) fn is_expression(self) -> bool {
|
|
self == Self::Expression
|
|
}
|
|
}
|
|
|
|
impl<'a> ParserImpl<'a> {
|
|
pub(crate) fn at_function_with_async(&mut self) -> bool {
|
|
self.at(Kind::Function)
|
|
|| self.at(Kind::Async)
|
|
&& self.peek_at(Kind::Function)
|
|
&& !self.peek_token().is_on_new_line
|
|
}
|
|
|
|
pub(crate) fn parse_function_body(&mut self) -> Result<Box<'a, FunctionBody<'a>>> {
|
|
let span = self.start_span();
|
|
self.expect(Kind::LCurly)?;
|
|
|
|
let (directives, statements) = self.context(Context::Return, Context::empty(), |p| {
|
|
p.parse_directives_and_statements(/* is_top_level */ false)
|
|
})?;
|
|
|
|
self.expect(Kind::RCurly)?;
|
|
Ok(self.ast.alloc_function_body(self.end_span(span), directives, statements))
|
|
}
|
|
|
|
pub(crate) fn parse_formal_parameters(
|
|
&mut self,
|
|
params_kind: FormalParameterKind,
|
|
) -> Result<(Option<TSThisParameter<'a>>, Box<'a, FormalParameters<'a>>)> {
|
|
let span = self.start_span();
|
|
self.expect(Kind::LParen)?;
|
|
let this_param = if self.ts_enabled() && self.at(Kind::This) {
|
|
let param = self.parse_ts_this_parameter()?;
|
|
if !self.at(Kind::RParen) {
|
|
self.expect(Kind::Comma)?;
|
|
}
|
|
Some(param)
|
|
} else {
|
|
None
|
|
};
|
|
let (list, rest) = self.parse_delimited_list_with_rest(
|
|
Kind::RParen,
|
|
Self::parse_formal_parameter,
|
|
Self::parse_rest_parameter,
|
|
)?;
|
|
self.expect(Kind::RParen)?;
|
|
let formal_parameters =
|
|
self.ast.alloc_formal_parameters(self.end_span(span), params_kind, list, rest);
|
|
Ok((this_param, formal_parameters))
|
|
}
|
|
|
|
fn parse_parameter_modifiers(&mut self) -> Modifiers<'a> {
|
|
let modifiers = self.parse_class_element_modifiers(true);
|
|
self.verify_modifiers(
|
|
&modifiers,
|
|
ModifierFlags::ACCESSIBILITY
|
|
.union(ModifierFlags::READONLY)
|
|
.union(ModifierFlags::OVERRIDE),
|
|
diagnostics::cannot_appear_on_a_parameter,
|
|
);
|
|
modifiers
|
|
}
|
|
|
|
fn parse_formal_parameter(&mut self) -> Result<FormalParameter<'a>> {
|
|
let span = self.start_span();
|
|
self.eat_decorators()?;
|
|
let modifiers = self.parse_parameter_modifiers();
|
|
let pattern = self.parse_binding_pattern_with_initializer()?;
|
|
let decorators = self.consume_decorators();
|
|
Ok(self.ast.formal_parameter(
|
|
self.end_span(span),
|
|
pattern,
|
|
modifiers.accessibility(),
|
|
modifiers.contains_readonly(),
|
|
modifiers.contains_override(),
|
|
decorators,
|
|
))
|
|
}
|
|
|
|
fn parse_rest_parameter(&mut self) -> Result<BindingRestElement<'a>> {
|
|
let element = self.parse_rest_element()?;
|
|
if self.at(Kind::Comma) {
|
|
if matches!(self.peek_kind(), Kind::RCurly | Kind::RBrack) {
|
|
let span = self.cur_token().span();
|
|
self.bump_any();
|
|
self.error(diagnostics::binding_rest_element_trailing_comma(span));
|
|
}
|
|
if !self.ctx.has_ambient() {
|
|
self.error(diagnostics::rest_parameter_last(element.span));
|
|
}
|
|
}
|
|
Ok(element)
|
|
}
|
|
|
|
pub(crate) fn parse_function(
|
|
&mut self,
|
|
span: Span,
|
|
id: Option<BindingIdentifier<'a>>,
|
|
r#async: bool,
|
|
generator: bool,
|
|
func_kind: FunctionKind,
|
|
modifiers: &Modifiers<'a>,
|
|
) -> Result<Box<'a, Function<'a>>> {
|
|
let ctx = self.ctx;
|
|
self.ctx = self.ctx.and_in(true).and_await(r#async).and_yield(generator);
|
|
|
|
let type_parameters = self.parse_ts_type_parameters()?;
|
|
|
|
let (this_param, params) =
|
|
self.parse_formal_parameters(FormalParameterKind::FormalParameter)?;
|
|
|
|
let return_type =
|
|
self.parse_ts_return_type_annotation(Kind::Colon, /* is_type */ true)?;
|
|
|
|
let body = if self.at(Kind::LCurly) { Some(self.parse_function_body()?) } else { None };
|
|
|
|
self.ctx =
|
|
self.ctx.and_in(ctx.has_in()).and_await(ctx.has_await()).and_yield(ctx.has_yield());
|
|
|
|
if !self.ts_enabled() && body.is_none() {
|
|
return Err(self.unexpected());
|
|
}
|
|
|
|
let function_type = match func_kind {
|
|
FunctionKind::Declaration | FunctionKind::DefaultExport => {
|
|
if body.is_none() {
|
|
FunctionType::TSDeclareFunction
|
|
} else {
|
|
FunctionType::FunctionDeclaration
|
|
}
|
|
}
|
|
FunctionKind::Expression { .. } => {
|
|
if body.is_none() {
|
|
FunctionType::TSEmptyBodyFunctionExpression
|
|
} else {
|
|
FunctionType::FunctionExpression
|
|
}
|
|
}
|
|
FunctionKind::TSDeclaration { .. } => FunctionType::TSDeclareFunction,
|
|
};
|
|
|
|
if FunctionType::TSDeclareFunction == function_type
|
|
|| FunctionType::TSEmptyBodyFunctionExpression == function_type
|
|
{
|
|
self.asi()?;
|
|
}
|
|
|
|
self.verify_modifiers(
|
|
modifiers,
|
|
ModifierFlags::DECLARE | ModifierFlags::ASYNC,
|
|
diagnostics::modifier_cannot_be_used_here,
|
|
);
|
|
|
|
Ok(self.ast.alloc_function(
|
|
function_type,
|
|
self.end_span(span),
|
|
id,
|
|
generator,
|
|
r#async,
|
|
modifiers.contains_declare(),
|
|
type_parameters,
|
|
this_param,
|
|
params,
|
|
body,
|
|
return_type,
|
|
))
|
|
}
|
|
|
|
/// [Function Declaration](https://tc39.es/ecma262/#prod-FunctionDeclaration)
|
|
pub(crate) fn parse_function_declaration(
|
|
&mut self,
|
|
stmt_ctx: StatementContext,
|
|
) -> Result<Statement<'a>> {
|
|
let func_kind = FunctionKind::Declaration;
|
|
let decl = self.parse_function_impl(func_kind)?;
|
|
if stmt_ctx.is_single_statement() {
|
|
if decl.r#async {
|
|
self.error(diagnostics::async_function_declaration(Span::new(
|
|
decl.span.start,
|
|
decl.params.span.end,
|
|
)));
|
|
} else if decl.generator {
|
|
self.error(diagnostics::generator_function_declaration(Span::new(
|
|
decl.span.start,
|
|
decl.params.span.end,
|
|
)));
|
|
}
|
|
}
|
|
|
|
Ok(Statement::FunctionDeclaration(decl))
|
|
}
|
|
|
|
/// Parse function implementation in Javascript, cursor
|
|
/// at `function` or `async function`
|
|
pub(crate) fn parse_function_impl(
|
|
&mut self,
|
|
func_kind: FunctionKind,
|
|
) -> Result<Box<'a, Function<'a>>> {
|
|
let span = self.start_span();
|
|
let r#async = self.eat(Kind::Async);
|
|
self.expect(Kind::Function)?;
|
|
let generator = self.eat(Kind::Star);
|
|
let id = self.parse_function_id(func_kind, r#async, generator)?;
|
|
self.parse_function(span, id, r#async, generator, func_kind, &Modifiers::empty())
|
|
}
|
|
|
|
/// Parse function implementation in Typescript, cursor
|
|
/// at `function`
|
|
pub(crate) fn parse_ts_function_impl(
|
|
&mut self,
|
|
start_span: Span,
|
|
func_kind: FunctionKind,
|
|
modifiers: &Modifiers<'a>,
|
|
) -> Result<Box<'a, Function<'a>>> {
|
|
let r#async = modifiers.contains(ModifierKind::Async);
|
|
self.expect(Kind::Function)?;
|
|
let generator = self.eat(Kind::Star);
|
|
let id = self.parse_function_id(func_kind, r#async, generator)?;
|
|
self.parse_function(start_span, id, r#async, generator, func_kind, modifiers)
|
|
}
|
|
|
|
/// [Function Expression](https://tc39.es/ecma262/#prod-FunctionExpression)
|
|
pub(crate) fn parse_function_expression(
|
|
&mut self,
|
|
span: Span,
|
|
r#async: bool,
|
|
) -> Result<Expression<'a>> {
|
|
let func_kind = FunctionKind::Expression;
|
|
self.expect(Kind::Function)?;
|
|
|
|
let generator = self.eat(Kind::Star);
|
|
let id = self.parse_function_id(func_kind, r#async, generator)?;
|
|
let function =
|
|
self.parse_function(span, id, r#async, generator, func_kind, &Modifiers::empty())?;
|
|
|
|
Ok(self.ast.expression_from_function(function))
|
|
}
|
|
|
|
/// Section 15.4 Method Definitions
|
|
/// `ClassElementName` ( `UniqueFormalParameters` ) { `FunctionBody` }
|
|
/// `GeneratorMethod`
|
|
/// * `ClassElementName`
|
|
/// `AsyncMethod`
|
|
/// async `ClassElementName`
|
|
/// `AsyncGeneratorMethod`
|
|
/// async * `ClassElementName`
|
|
pub(crate) fn parse_method(
|
|
&mut self,
|
|
r#async: bool,
|
|
generator: bool,
|
|
) -> Result<Box<'a, Function<'a>>> {
|
|
let span = self.start_span();
|
|
self.parse_function(
|
|
span,
|
|
None,
|
|
r#async,
|
|
generator,
|
|
FunctionKind::Expression,
|
|
&Modifiers::empty(),
|
|
)
|
|
}
|
|
|
|
/// Section 15.5 Yield Expression
|
|
/// yield
|
|
/// yield [no `LineTerminator` here] `AssignmentExpression`
|
|
/// yield [no `LineTerminator` here] * `AssignmentExpression`
|
|
pub(crate) fn parse_yield_expression(&mut self) -> Result<Expression<'a>> {
|
|
let span = self.start_span();
|
|
self.bump_any(); // advance `yield`
|
|
|
|
let has_yield = self.ctx.has_yield();
|
|
if !has_yield {
|
|
self.error(diagnostics::yield_expression(Span::new(span.start, span.start + 5)));
|
|
}
|
|
|
|
let mut delegate = false;
|
|
let mut argument = None;
|
|
|
|
if !self.cur_token().is_on_new_line {
|
|
delegate = self.eat(Kind::Star);
|
|
let not_assignment_expr = matches!(
|
|
self.cur_kind(),
|
|
Kind::Semicolon
|
|
| Kind::Eof
|
|
| Kind::RCurly
|
|
| Kind::RParen
|
|
| Kind::RBrack
|
|
| Kind::Colon
|
|
| Kind::Comma
|
|
);
|
|
if !not_assignment_expr || delegate {
|
|
self.ctx = self.ctx.union_yield_if(true);
|
|
argument = Some(self.parse_assignment_expression_or_higher()?);
|
|
self.ctx = self.ctx.and_yield(has_yield);
|
|
}
|
|
}
|
|
|
|
Ok(self.ast.expression_yield(self.end_span(span), delegate, argument))
|
|
}
|
|
|
|
// id: None - for AnonymousDefaultExportedFunctionDeclaration
|
|
pub(crate) fn parse_function_id(
|
|
&mut self,
|
|
kind: FunctionKind,
|
|
r#async: bool,
|
|
generator: bool,
|
|
) -> Result<Option<BindingIdentifier<'a>>> {
|
|
let ctx = self.ctx;
|
|
if kind.is_expression() {
|
|
self.ctx = self.ctx.and_await(r#async).and_yield(generator);
|
|
}
|
|
let id = self.cur_kind().is_binding_identifier().then(|| {
|
|
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
|
self.check_identifier(span, &name);
|
|
BindingIdentifier { span, name, symbol_id: Cell::default() }
|
|
});
|
|
self.ctx = ctx;
|
|
|
|
if kind.is_id_required() && id.is_none() {
|
|
match self.cur_kind() {
|
|
Kind::LParen => {
|
|
self.error(diagnostics::expect_function_name(self.cur_token().span()));
|
|
}
|
|
kind if kind.is_reserved_keyword() => self.expect_without_advance(Kind::Ident)?,
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
Ok(id)
|
|
}
|
|
}
|