Skip to content

Commit

Permalink
combine into one function
Browse files Browse the repository at this point in the history
  • Loading branch information
Dunqing committed Nov 14, 2024
1 parent 32deb87 commit 3ee0724
Showing 1 changed file with 66 additions and 104 deletions.
170 changes: 66 additions & 104 deletions crates/oxc_transformer/src/es2020/optional_chaining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct OptionalChainingTransformContext<'a, 't> {
temp_binding: Option<BoundIdentifier<'a>>,
check_mode: CheckMode,
}

impl<'a, 't> OptionalChainingTransformContext<'a, 't> {
fn new(ctx: &'t mut TraverseCtx<'a>) -> Self {
let check_mode =
Expand All @@ -52,7 +53,7 @@ impl<'a, 't> OptionalChainingTransformContext<'a, 't> {
self.check_mode == CheckMode::Void0
}

pub fn replace_temp_binding<F: FnOnce(&mut Self) -> BoundIdentifier<'a>>(
pub fn set_temp_binding<F: FnOnce(&mut Self) -> BoundIdentifier<'a>>(
&mut self,
get_binding: F,
) {
Expand Down Expand Up @@ -141,132 +142,100 @@ impl<'a, 'ctx> OptionalChaining<'a, 'ctx> {
match chain_element {
ChainElement::CallExpression(call) => {
let mut expr = Expression::CallExpression(call);
let left = self.transform_optional_call_expression(&mut expr, ctx).unwrap();
let left = self.transform_optional_expression_recursion(&mut expr, ctx).unwrap();
Self::create_logical_expression(left, expr, ctx)
}
match_member_expression!(ChainElement) => {
let mut expr = Expression::from(chain_element.into_member_expression());
let left = self.transform_optional_member_expression(&mut expr, ctx).unwrap();
let left = self.transform_optional_expression_recursion(&mut expr, ctx).unwrap();
Self::create_logical_expression(left, expr, ctx)
}
}
}

fn transform_optional_member_expression<'t>(
fn transform_optional_expression_recursion<'t>(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Option<Expression<'a>> {
let member = expr.as_member_expression_mut()?;
let is_optional = member.optional();

if is_optional {
match member {
MemberExpression::ComputedMemberExpression(m) => m.optional = false,
MemberExpression::StaticMemberExpression(m) => m.optional = false,
MemberExpression::PrivateFieldExpression(m) => m.optional = false,
// Go deeper into the member expression and transform it and return the result
let (result, optional_expr) = match expr {
Expression::ComputedMemberExpression(m) => {
let deep = self.transform_optional_expression_recursion(&mut m.object, ctx);
if m.optional {
m.optional = false;
(deep, &mut m.object)
} else {
return deep;
}
}
}

let object = member.object_mut().get_inner_expression_mut();

// Continue going down the deepest
let transformed_part = self.transform_next_part(object, ctx);

if !is_optional {
return transformed_part;
}

if let Some(node) = transformed_part {
Some(self.generate_memoised_and_assign_to_it_and_check(node, object, ctx))
} else {
Some(self.transform_optional_expression(object, ctx))
}
}
Expression::StaticMemberExpression(m) => {
let deep = self.transform_optional_expression_recursion(&mut m.object, ctx);
if m.optional {
m.optional = false;
(deep, &mut m.object)
} else {
return deep;
}
}
Expression::PrivateFieldExpression(m) => {
let deep = self.transform_optional_expression_recursion(&mut m.object, ctx);
if m.optional {
m.optional = false;
(deep, &mut m.object)
} else {
return deep;
}
}
Expression::CallExpression(c) => {
let deep = self.transform_optional_expression_recursion(&mut c.callee, ctx);
if c.optional {
c.optional = false;
(deep, &mut c.callee)
} else {
return deep;
}
}
_ => return None,
};

fn transform_optional_expression<'t>(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Expression<'a> {
if let Expression::Identifier(ident) = expr {
let left1 =
Expression::Identifier(ctx.ast.alloc(
let result = match (result, optional_expr) {
(Some(result), expr) => {
self.generate_memoised_and_assign_to_it_and_check(result, expr, ctx)
}
(None, Expression::Identifier(ident)) => {
let left1 = Expression::Identifier(ctx.ast.alloc(
ctx.traverse_ctx.clone_identifier_reference(ident, ReferenceFlags::Read),
));
let left2 =
Expression::Identifier(ctx.ast.alloc(
let left2 = Expression::Identifier(ctx.ast.alloc(
ctx.traverse_ctx.clone_identifier_reference(ident, ReferenceFlags::Read),
));
Self::wrap_check(left1, left2, ctx)
} else {
ctx.replace_temp_binding(|ctx| {
self.maybe_generate_memoised(expr, ctx).unwrap_or_else(|| {
ctx.traverse_ctx.generate_uid_in_current_scope_based_on_node(
expr,
SymbolFlags::FunctionScopedVariable,
)
})
});

let expr = mem::replace(expr, ctx.create_read_expression());
let assignment_expression = Self::create_assignment_expression(expr, ctx);
let expr = Self::wrap_check(assignment_expression, ctx.create_read_expression(), ctx);
expr
}
}

fn transform_next_part<'t>(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Option<Expression<'a>> {
match expr {
match_member_expression!(Expression) => {
self.transform_optional_member_expression(expr, ctx)
Self::wrap_check(left1, left2, ctx)
}
Expression::CallExpression(_) => self.transform_optional_call_expression(expr, ctx),
_ => None,
}
}

fn transform_optional_call_expression<'t>(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Option<Expression<'a>> {
let Expression::CallExpression(call) = expr else { unreachable!() };
let transformed_part = self.transform_next_part(&mut call.callee, ctx);

if !call.optional {
return transformed_part;
}

call.optional = false;
(_, expr) => {
ctx.set_temp_binding(|ctx| self.maybe_generate_memoised(expr, ctx));

let expr = mem::replace(expr, ctx.create_read_expression());
let assignment_expression = Self::create_assignment_expression(expr, ctx);
let expr =
Self::wrap_check(assignment_expression, ctx.create_read_expression(), ctx);
expr
}
};

if let Some(node) = transformed_part {
Some(self.generate_memoised_and_assign_to_it_and_check(node, &mut call.callee, ctx))
} else {
Some(self.transform_optional_expression(&mut call.callee, ctx))
}
Some(result)
}

fn maybe_generate_memoised<'t>(
&mut self,
expr: &Expression<'a>,
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Option<BoundIdentifier<'a>> {
if ctx.traverse_ctx.is_static(expr) {
return None;
}

// var _name;
) -> BoundIdentifier<'a> {
let binding = ctx
.traverse_ctx
.generate_uid_in_current_scope_based_on_node(expr, SymbolFlags::FunctionScopedVariable);
self.ctx.var_declarations.insert_var(&binding, None, ctx.traverse_ctx);

Some(binding)
binding
}

fn create_assignment_expression<'t>(
Expand Down Expand Up @@ -326,14 +295,7 @@ impl<'a, 'ctx> OptionalChaining<'a, 'ctx> {
ctx: &mut OptionalChainingTransformContext<'a, 't>,
) -> Expression<'a> {
if ctx.temp_binding.is_none() {
ctx.replace_temp_binding(|ctx| {
self.maybe_generate_memoised(object, ctx).unwrap_or_else(|| {
ctx.traverse_ctx.generate_uid_in_current_scope_based_on_node(
object,
SymbolFlags::FunctionScopedVariable,
)
})
});
ctx.set_temp_binding(|ctx| self.maybe_generate_memoised(object, ctx));
}

let object = mem::replace(object, ctx.create_read_expression());
Expand Down

0 comments on commit 3ee0724

Please sign in to comment.