Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(transformer): finish exponentiation operator
Browse files Browse the repository at this point in the history
Boshen committed Oct 15, 2023
1 parent 6c18b3e commit 61a11de
Showing 17 changed files with 376 additions and 82 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 22 additions & 22 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
@@ -92,29 +92,18 @@ pub enum Expression<'a> {
impl<'a> Expression<'a> {
/// `PrimaryExpression`
/// [tc39/ecma262#prod-PrimaryExpression](https://tc39.es/ecma262/#prod-PrimaryExpression)
#[rustfmt::skip]
pub fn is_primary_expression(&self) -> bool {
self.is_literal_expression()
|| matches!(
self,
Self::Identifier(_)
| Self::ThisExpression(_)
| Self::FunctionExpression(_)
| Self::ClassExpression(_)
| Self::ParenthesizedExpression(_)
| Self::ArrayExpression(_)
| Self::ObjectExpression(_)
)
}

pub fn is_literal_expression(&self) -> bool {
matches!(
self,
Self::BooleanLiteral(_)
| Self::NullLiteral(_)
| Self::NumberLiteral(_)
| Self::BigintLiteral(_)
| Self::RegExpLiteral(_)
| Self::StringLiteral(_) // TemplateLiteral is not `Literal` type per oxc_ast
self.is_literal() || matches!(self, Self::Identifier(_) | Self::ThisExpression(_) | Self::FunctionExpression(_)
| Self::ClassExpression(_) | Self::ParenthesizedExpression(_)
| Self::ArrayExpression(_) | Self::ObjectExpression(_))
}

#[rustfmt::skip]
pub fn is_literal(&self) -> bool {
// Note: TemplateLiteral is not `Literal`
matches!(self, Self::BooleanLiteral(_) | Self::NullLiteral(_) | Self::NumberLiteral(_)
| Self::BigintLiteral(_) | Self::RegExpLiteral(_) | Self::StringLiteral(_)
)
}

@@ -540,6 +529,10 @@ pub enum MemberExpression<'a> {
}

impl<'a> MemberExpression<'a> {
pub fn is_computed(&self) -> bool {
matches!(self, MemberExpression::ComputedMemberExpression(_))
}

pub fn optional(&self) -> bool {
match self {
MemberExpression::ComputedMemberExpression(expr) => expr.optional,
@@ -814,6 +807,13 @@ impl<'a> AssignmentTarget<'a> {
pub fn is_destructuring_pattern(&self) -> bool {
matches!(self, Self::AssignmentTargetPattern(_))
}

pub fn is_identifier(&self) -> bool {
matches!(
self,
Self::SimpleAssignmentTarget(SimpleAssignmentTarget::AssignmentTargetIdentifier(_))
)
}
}

#[derive(Debug, Hash)]
4 changes: 4 additions & 0 deletions crates/oxc_ast/src/ast/literal.rs
Original file line number Diff line number Diff line change
@@ -211,6 +211,10 @@ pub struct StringLiteral {
}

impl StringLiteral {
pub fn new(span: Span, value: Atom) -> Self {
Self { span, value }
}

/// Static Semantics: `IsStringWellFormedUnicode`
/// test for \uD800-\uDFFF
pub fn is_string_well_formed_unicode(&self) -> bool {
58 changes: 47 additions & 11 deletions crates/oxc_ast/src/ast_builder.rs
Original file line number Diff line number Diff line change
@@ -77,6 +77,16 @@ impl<'a> AstBuilder<'a> {
mem::replace(stmts, self.new_vec())
}

pub fn move_assignment_target(
&self,
target: &mut AssignmentTarget<'a>,
) -> AssignmentTarget<'a> {
let ident = IdentifierReference::new(Span::default(), "".into());
let dummy = self.simple_assignment_target_identifier(ident);
let dummy = AssignmentTarget::SimpleAssignmentTarget(dummy);
mem::replace(target, dummy)
}

pub fn program(
&self,
span: Span,
@@ -90,10 +100,6 @@ impl<'a> AstBuilder<'a> {

/* ---------- Literals ---------- */

pub fn string_literal(&self, span: Span, value: Atom) -> StringLiteral {
StringLiteral { span, value }
}

pub fn number_literal(
&self,
span: Span,
@@ -415,6 +421,13 @@ impl<'a> AstBuilder<'a> {
SimpleAssignmentTarget::AssignmentTargetIdentifier(self.alloc(ident))
}

pub fn simple_assignment_target_member_expression(
&self,
expr: MemberExpression<'a>,
) -> SimpleAssignmentTarget<'a> {
SimpleAssignmentTarget::MemberAssignmentTarget(self.alloc(expr))
}

pub fn await_expression(&self, span: Span, argument: Expression<'a>) -> Expression<'a> {
Expression::AwaitExpression(self.alloc(AwaitExpression { span, argument }))
}
@@ -496,31 +509,54 @@ impl<'a> AstBuilder<'a> {
Expression::MemberExpression(self.alloc(expr))
}

pub fn computed_member(
&self,
span: Span,
object: Expression<'a>,
expression: Expression<'a>,
optional: bool, // for optional chaining
) -> MemberExpression<'a> {
MemberExpression::ComputedMemberExpression(ComputedMemberExpression {
span,
object,
expression,
optional,
})
}

pub fn computed_member_expression(
&self,
span: Span,
object: Expression<'a>,
expression: Expression<'a>,
optional: bool, // for optional chaining
) -> Expression<'a> {
self.member_expression(MemberExpression::ComputedMemberExpression(
ComputedMemberExpression { span, object, expression, optional },
))
self.member_expression(self.computed_member(span, object, expression, optional))
}

pub fn static_member_expression(
pub fn static_member(
&self,
span: Span,
object: Expression<'a>,
property: IdentifierName,
optional: bool, // for optional chaining
) -> Expression<'a> {
self.member_expression(MemberExpression::StaticMemberExpression(StaticMemberExpression {
) -> MemberExpression<'a> {
MemberExpression::StaticMemberExpression(StaticMemberExpression {
span,
object,
property,
optional,
}))
})
}

pub fn static_member_expression(
&self,
span: Span,
object: Expression<'a>,
property: IdentifierName,
optional: bool, // for optional chaining
) -> Expression<'a> {
self.member_expression(self.static_member(span, object, property, optional))
}

pub fn private_field_expression(
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/ast_util.rs
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ pub fn is_static_boolean<'a>(expr: &Expression<'a>, ctx: &LintContext<'a>) -> bo
/// Checks if a branch node of `LogicalExpression` short circuits the whole condition
fn is_logical_identity(op: LogicalOperator, expr: &Expression) -> bool {
match expr {
expr if expr.is_literal_expression() => {
expr if expr.is_literal() => {
let boolean_value = expr.get_boolean_value();
(op == LogicalOperator::Or && boolean_value == Some(true))
|| (op == LogicalOperator::And && boolean_value == Some(false))
@@ -142,7 +142,7 @@ impl<'a, 'b> IsConstant<'a, 'b> for Expression<'a> {
Self::Identifier(ident) => {
ident.name == "undefined" && ctx.semantic().is_reference_to_global_variable(ident)
}
_ if self.is_literal_expression() => true,
_ if self.is_literal() => true,
_ => false,
}
}
Original file line number Diff line number Diff line change
@@ -167,7 +167,7 @@ impl NoConstantBinaryExpression {
| Expression::UpdateExpression(_)
| Expression::BinaryExpression(_)
| Expression::UnaryExpression(_) => true,
expr if expr.is_literal_expression() => true,
expr if expr.is_literal() => true,
Expression::CallExpression(call_expr) => {
if let Expression::Identifier(ident) = &call_expr.callee {
return ["Boolean", "String", "Number"].contains(&ident.name.as_str())
@@ -267,7 +267,7 @@ impl NoConstantBinaryExpression {
Expression::ParenthesizedExpression(paren_expr) => {
Self::has_constant_loose_boolean_comparison(&paren_expr.expression, ctx)
}
expr if expr.is_literal_expression() => true,
expr if expr.is_literal() => true,
expr if expr.evaluate_to_undefined() => true,
_ => false,
}
@@ -288,7 +288,7 @@ impl NoConstantBinaryExpression {
| Expression::NewExpression(_)
| Expression::TemplateLiteral(_)
| Expression::UpdateExpression(_) => true,
expr if expr.is_literal_expression() => true,
expr if expr.is_literal() => true,
Expression::BinaryExpression(binary_expr) => {
binary_expr.operator.is_numeric_or_string_binary_operator()
}
4 changes: 2 additions & 2 deletions crates/oxc_minifier/src/compressor/fold.rs
Original file line number Diff line number Diff line change
@@ -264,7 +264,7 @@ impl<'a> Compressor<'a> {
let right_string = get_string_value(right)?;
// let value = left_string.to_owned().
let value = left_string + right_string;
let string_literal = self.ast.string_literal(span, Atom::from(value));
let string_literal = StringLiteral::new(span, Atom::from(value));
Some(self.ast.literal_string_expression(string_literal))
},

@@ -587,7 +587,7 @@ impl<'a> Compressor<'a> {
};

if let Some(type_name) = type_name {
let string_literal = self.ast.string_literal(span, Atom::from(type_name));
let string_literal = StringLiteral::new(span, Atom::from(type_name));
return Some(self.ast.literal_string_expression(string_literal));
}
}
4 changes: 4 additions & 0 deletions crates/oxc_semantic/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -92,6 +92,10 @@ impl SymbolTable {
&self.references[reference_id]
}

pub fn has_binding(&self, reference_id: ReferenceId) -> bool {
self.references[reference_id].symbol_id().is_some()
}

pub fn is_global_reference(&self, reference_id: ReferenceId) -> bool {
self.references[reference_id].symbol_id().is_none()
}
10 changes: 7 additions & 3 deletions crates/oxc_transformer/examples/transformer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{env, path::Path};
use std::{cell::RefCell, env, path::Path, rc::Rc};

use oxc_allocator::Allocator;
use oxc_codegen::{Codegen, CodegenOptions};
@@ -34,12 +34,16 @@ fn main() {
println!("{printed}");

let program = allocator.alloc(ret.program);
let _ = SemanticBuilder::new(&source_text, source_type).build(program);

let semantic = SemanticBuilder::new(&source_text, source_type).build(program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));

let transform_options = TransformOptions {
target: TransformTarget::ES2015,
react: Some(TransformReactOptions::default()),
};
Transformer::new(&allocator, source_type, transform_options).build(program);
Transformer::new(&allocator, source_type, &symbols, transform_options).build(program);
let printed = Codegen::<false>::new(source_text.len(), codegen_options).build(program);
println!("Transformed:\n");
println!("{printed}");
Loading

0 comments on commit 61a11de

Please sign in to comment.