Skip to content

Commit

Permalink
Transform private field expressions WIP 1
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Nov 15, 2024
1 parent 26b2557 commit da23b14
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 4 deletions.
2 changes: 2 additions & 0 deletions crates/oxc_transformer/src/common/helper_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub enum Helper {
WrapAsyncGenerator,
DefineProperty,
ClassPrivateFieldInitSpec,
ClassPrivateFieldGet,
}

impl Helper {
Expand All @@ -158,6 +159,7 @@ impl Helper {
Self::WrapAsyncGenerator => "wrapAsyncGenerator",
Self::DefineProperty => "defineProperty",
Self::ClassPrivateFieldInitSpec => "classPrivateFieldInitSpec",
Self::ClassPrivateFieldGet => "classPrivateFieldGet",
}
}
}
Expand Down
68 changes: 64 additions & 4 deletions crates/oxc_transformer/src/es2022/class_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
use rustc_hash::FxHashMap;
use serde::Deserialize;

use oxc_allocator::{Address, GetAddress};
use oxc_allocator::{Address, Box as ArenaBox, GetAddress};
use oxc_ast::{ast::*, NONE};
use oxc_data_structures::stack::SparseStack;
use oxc_span::SPAN;
Expand Down Expand Up @@ -169,10 +169,18 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
}

impl<'a, 'ctx> Traverse<'a> for ClassProperties<'a, 'ctx> {
// ---------- Class transform ----------

fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
if let Expression::ClassExpression(class) = expr {
self.transform_class_expression_start(class, ctx);
self.transform_class_expression_finish(expr, ctx);
match expr {
Expression::ClassExpression(class) => {
self.transform_class_expression_start(class, ctx);
self.transform_class_expression_finish(expr, ctx);
}
Expression::PrivateFieldExpression(_) => {
self.transform_private_field_expression(expr, ctx);
}
_ => {}
}
}

Expand Down Expand Up @@ -922,6 +930,58 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
class.body.body.insert(0, ctor);
}

// ---------- Private properties transform ----------

/// Transform private field expression.
///
/// `this.#x` -> `_classPrivateFieldGet(_x, this)`.
// `#[inline]` so that compiler sees that `expr` is an `Expression::PrivateFieldExpression`.
#[inline]
fn transform_private_field_expression(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
let owned_expr = ctx.ast.move_expression(expr);
let Expression::PrivateFieldExpression(field_expr) = owned_expr else { unreachable!() };
*expr = self.transform_private_field_expression_impl(field_expr, ctx);
}

fn transform_private_field_expression_impl(
&self,
field_expr: ArenaBox<'a, PrivateFieldExpression<'a>>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let field_expr = field_expr.unbox();

let prop = self.lookup_private_property(&field_expr.field);
if prop.is_static && false {
// TODO
todo!();
} else {
let arguments = ctx.ast.vec_from_iter([
Argument::from(prop.binding.create_read_expression(ctx)),
Argument::from(field_expr.object),
]);
self.ctx.helper_call_expr(Helper::ClassPrivateFieldGet, field_expr.span, arguments, ctx)
}
}

fn lookup_private_property(&self, ident: &PrivateIdentifier<'a>) -> &PrivateProp<'a> {
// Check for binding in closest class first, then enclosing classes
// TODO: Check there are tests for bindings in enclosing classes.
for props in self.private_props_stack.as_slice().iter().rev() {
if let Some(prop) = props.get(&ident.name) {
return prop;
}
}
// It's a syntax error for a private property to be used if it's not defined in the class
// TODO: Record an error instead
unreachable!();
}

// ---------- Utility methods ----------

/// `super(...args);`
fn create_super_call_stmt(
binding: &BoundIdentifier<'a>,
Expand Down

0 comments on commit da23b14

Please sign in to comment.