Skip to content

Commit

Permalink
Member expressions WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Apr 23, 2024
1 parent fcc8ffd commit c730ea3
Show file tree
Hide file tree
Showing 8 changed files with 699 additions and 26 deletions.
483 changes: 482 additions & 1 deletion src/ast.rs

Large diffs are not rendered by default.

27 changes: 20 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod parser;
mod print;
mod semantic;
mod traverse;
mod util;
mod visit;
use ast::{
traversable::{Expression, Parent, UnaryExpression},
Expand Down Expand Up @@ -70,7 +71,10 @@ mod tests {

#[test]
fn mutate_standard_ast_after_transform() {
use ast::{Expression, IdentifierReference, Parent, Statement, StringLiteral};
use ast::{
Expression, IdentifierReference, MemberExpression, Parent, Statement,
StaticMemberExpression, StringLiteral,
};
use oxc_allocator::Box;
use std::mem;

Expand Down Expand Up @@ -102,12 +106,21 @@ mod tests {
};
unary_expr.operator = UnaryOperator::UnaryNegation;

let id = if let Expression::Identifier(unary_expr) = &mut unary_expr.argument {
&mut **unary_expr
} else {
unreachable!();
};
id.name = "bar";
let member_expr =
if let Expression::MemberExpression(member_expr) = &mut unary_expr.argument {
&mut **member_expr
} else {
unreachable!();
};
*member_expr = MemberExpression::StaticMemberExpression(StaticMemberExpression {
object: Expression::Identifier(Box(alloc.alloc(IdentifierReference {
name: "foo",
parent: Parent::None,
}))),
property: "bar",
optional: false,
parent: Parent::None,
});

unary_expr.argument = Expression::StringLiteral(Box(alloc.alloc(StringLiteral {
value: "foo",
Expand Down
39 changes: 28 additions & 11 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
use oxc_allocator::{Allocator, Box, Vec};

use crate::ast::{
BinaryExpression, BinaryOperator, Expression, ExpressionStatement, IdentifierReference, Parent,
Program, Statement, StringLiteral, UnaryExpression, UnaryOperator,
BinaryExpression, BinaryOperator, ComputedMemberExpression, Expression, ExpressionStatement,
IdentifierReference, MemberExpression, Parent, Program, Statement, StringLiteral,
UnaryExpression, UnaryOperator,
};

/// Create AST for `typeof foo === 'object'`.
/// Create AST for `typeof foo[bar] === 'object'`.
/// Hard-coded here, but these are the steps actual parser would take to create the AST.
pub fn parse(alloc: &Allocator) -> &mut Program {
// `foo`
let id = Box(alloc.alloc(IdentifierReference {
let id = Expression::Identifier(Box(alloc.alloc(IdentifierReference {
name: "foo",
parent: Parent::None,
}));
})));

// `bar`
let id2 = Expression::Identifier(Box(alloc.alloc(IdentifierReference {
name: "bar",
parent: Parent::None,
})));

// `foo[bar]`
let member_expr = Expression::MemberExpression(Box(alloc.alloc(
MemberExpression::ComputedMemberExpression(ComputedMemberExpression {
object: id,
expression: id2,
optional: false,
parent: Parent::None,
}),
)));

// `typeof foo`
// `typeof foo[bar]`
let unary_expr = Box(alloc.alloc(UnaryExpression {
operator: UnaryOperator::Typeof,
argument: Expression::Identifier(id),
argument: member_expr,
parent: Parent::None,
}));

Expand All @@ -27,24 +44,24 @@ pub fn parse(alloc: &Allocator) -> &mut Program {
parent: Parent::None,
}));

// `typeof foo === 'object'` (as expression)
// `typeof foo[bar] === 'object'` (as expression)
let binary_expr = Box(alloc.alloc(BinaryExpression {
operator: BinaryOperator::StrictEquality,
left: Expression::UnaryExpression(unary_expr),
right: Expression::StringLiteral(str_lit),
parent: Parent::None,
}));

// `typeof foo === 'object'` (as expression statement)
// `typeof foo[bar] === 'object'` (as expression statement)
let expr_stmt = Box(alloc.alloc(ExpressionStatement {
expression: Expression::BinaryExpression(binary_expr),
parent: Parent::None,
}));

// `typeof foo === 'object'` (as statement)
// `typeof foo[bar] === 'object'` (as statement)
let stmt = Statement::ExpressionStatement(expr_stmt);

// `typeof foo === 'object'` (as program)
// `typeof foo[bar] === 'object'` (as program)
let mut body = Vec::new_in(alloc);
body.push(stmt);
let program = alloc.alloc(Program { body });
Expand Down
25 changes: 23 additions & 2 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
ast::{
BinaryExpression, BinaryOperator, ExpressionStatement, IdentifierReference, Program,
StringLiteral, UnaryExpression, UnaryOperator,
BinaryExpression, BinaryOperator, ComputedMemberExpression, ExpressionStatement,
IdentifierReference, Program, StaticMemberExpression, StringLiteral, UnaryExpression,
UnaryOperator,
},
Visit,
};
Expand Down Expand Up @@ -65,4 +66,24 @@ impl<'a> Visit<'a> for Printer {
));
self.visit_expression(&bin_expr.right);
}

fn visit_computed_member_expression(&mut self, expr: &ComputedMemberExpression<'a>) {
self.visit_expression(&expr.object);
if expr.optional {
self.output("?.");
}
self.output("[");
self.visit_expression(&expr.expression);
self.output("]");
}

fn visit_static_member_expression(&mut self, expr: &StaticMemberExpression<'a>) {
self.visit_expression(&expr.object);
if expr.optional {
self.output("?.");
} else {
self.output(".");
}
self.output(expr.property);
}
}
31 changes: 29 additions & 2 deletions src/semantic.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{
ast::{
traversable::{
BinaryExpression, ExpressionStatement, IdentifierReference, Parent,
Program as TraversableProgram, StringLiteral, UnaryExpression,
BinaryExpression, ComputedMemberExpression, ExpressionStatement, IdentifierReference,
Parent, Program as TraversableProgram, StaticMemberExpression, StringLiteral,
UnaryExpression,
},
Program,
},
Expand Down Expand Up @@ -82,4 +83,30 @@ impl<'a> Traverse<'a> for Semantic<'a> {
self.current_parent = Parent::UnaryExpressionArgument(unary_expr);
self.walk_unary_expression(unary_expr, tk);
}

fn visit_computed_member_expression(
&mut self,
expr: SharedBox<'a, ComputedMemberExpression<'a>>,
tk: &mut Token,
) {
let expr_mut = expr.borrow_mut(tk);
// SAFETY: We are here establishing the invariant of correct parent tracking
unsafe { expr_mut.set_parent(self.current_parent) };
self.current_parent = Parent::ComputedMemberExpressionObject(expr);
self.visit_expression(expr.object(tk), tk);
self.current_parent = Parent::ComputedMemberExpressionExpression(expr);
self.visit_expression(expr.expression(tk), tk);
}

fn visit_static_member_expression(
&mut self,
expr: SharedBox<'a, StaticMemberExpression<'a>>,
tk: &mut Token,
) {
let expr_mut = expr.borrow_mut(tk);
// SAFETY: We are here establishing the invariant of correct parent tracking
unsafe { expr_mut.set_parent(self.current_parent) };
self.current_parent = Parent::StaticMemberExpressionObject(expr);
self.visit_expression(expr.object(tk), tk);
}
}
66 changes: 64 additions & 2 deletions src/traverse.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::{
ast::{
traversable::{
BinaryExpression, Expression, ExpressionStatement, IdentifierReference,
Program as TraversableProgram, Statement, StringLiteral, UnaryExpression,
BinaryExpression, ComputedMemberExpression, Expression, ExpressionStatement,
IdentifierReference, MemberExpression, MemberExpressionRef,
Program as TraversableProgram, Statement, StaticMemberExpression, StringLiteral,
UnaryExpression,
},
Program,
},
Expand Down Expand Up @@ -107,6 +109,9 @@ pub trait Traverse<'a> {
Expression::UnaryExpression(unary_expr) => {
self.visit_unary_expression(unary_expr, tk);
}
Expression::MemberExpression(member_expr) => {
self.visit_member_expression(member_expr, tk);
}
Expression::Dummy => unreachable!(),
}
}
Expand Down Expand Up @@ -154,4 +159,61 @@ pub trait Traverse<'a> {
) {
self.visit_expression(unary_expr.argument(tk), tk);
}

fn visit_member_expression(
&mut self,
member_expr: SharedBox<'a, MemberExpression<'a>>,
tk: &mut Token,
) {
self.walk_member_expression(member_expr, tk);
}

fn walk_member_expression(
&mut self,
member_expr: SharedBox<'a, MemberExpression<'a>>,
tk: &mut Token,
) {
match member_expr.as_payload_ref(tk) {
MemberExpressionRef::ComputedMemberExpression(expr) => {
self.visit_computed_member_expression(expr, tk);
}
MemberExpressionRef::StaticMemberExpression(expr) => {
self.visit_static_member_expression(expr, tk);
}
MemberExpressionRef::Dummy => unreachable!(),
};
}

fn visit_computed_member_expression(
&mut self,
expr: SharedBox<'a, ComputedMemberExpression<'a>>,
tk: &mut Token,
) {
self.walk_computed_member_expression(expr, tk);
}

fn walk_computed_member_expression(
&mut self,
expr: SharedBox<'a, ComputedMemberExpression<'a>>,
tk: &mut Token,
) {
self.visit_expression(expr.object(tk), tk);
self.visit_expression(expr.expression(tk), tk);
}

fn visit_static_member_expression(
&mut self,
expr: SharedBox<'a, StaticMemberExpression<'a>>,
tk: &mut Token,
) {
self.walk_static_member_expression(expr, tk);
}

fn walk_static_member_expression(
&mut self,
expr: SharedBox<'a, StaticMemberExpression<'a>>,
tk: &mut Token,
) {
self.visit_expression(expr.object(tk), tk);
}
}
15 changes: 15 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// Const fn to get maximum value in a slice of `usize`s
pub const fn max_all(values: &[usize]) -> usize {
let mut max = 0;
let mut i = 0;
loop {
if i == values.len() {
break;
}
if values[i] > max {
max = values[i];
}
i += 1;
}
max
}
39 changes: 38 additions & 1 deletion src/visit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use oxc_allocator::Vec;

use crate::ast::{
BinaryExpression, Expression, ExpressionStatement, IdentifierReference, Program, Statement,
BinaryExpression, ComputedMemberExpression, Expression, ExpressionStatement,
IdentifierReference, MemberExpression, Program, Statement, StaticMemberExpression,
StringLiteral, UnaryExpression,
};

Expand Down Expand Up @@ -62,6 +63,9 @@ pub trait Visit<'a> {
Expression::UnaryExpression(unary_expr) => {
self.visit_unary_expression(unary_expr);
}
Expression::MemberExpression(member_expr) => {
self.visit_member_expression(member_expr);
}
Expression::Dummy => unreachable!(),
}
}
Expand All @@ -88,4 +92,37 @@ pub trait Visit<'a> {
fn walk_unary_expression(&mut self, unary_expr: &UnaryExpression<'a>) {
self.visit_expression(&unary_expr.argument);
}

fn visit_member_expression(&mut self, member_expr: &MemberExpression<'a>) {
self.walk_member_expression(member_expr);
}

fn walk_member_expression(&mut self, member_expr: &MemberExpression<'a>) {
match member_expr {
MemberExpression::ComputedMemberExpression(expr) => {
self.visit_computed_member_expression(expr);
}
MemberExpression::StaticMemberExpression(expr) => {
self.visit_static_member_expression(expr);
}
MemberExpression::Dummy => unreachable!(),
}
}

fn visit_computed_member_expression(&mut self, expr: &ComputedMemberExpression<'a>) {
self.walk_computed_member_expression(expr);
}

fn walk_computed_member_expression(&mut self, expr: &ComputedMemberExpression<'a>) {
self.visit_expression(&expr.object);
self.visit_expression(&expr.expression);
}

fn visit_static_member_expression(&mut self, expr: &StaticMemberExpression<'a>) {
self.walk_static_member_expression(expr);
}

fn walk_static_member_expression(&mut self, expr: &StaticMemberExpression<'a>) {
self.visit_expression(&expr.object);
}
}

0 comments on commit c730ea3

Please sign in to comment.