From 45b925c7584275043d4ff6016d04beb7bff46c68 Mon Sep 17 00:00:00 2001 From: Boshen Date: Thu, 12 Oct 2023 13:46:35 +0800 Subject: [PATCH] feat(codegen): move minifying printer to codegen crate --- .github/labeler.yml | 2 +- Cargo.lock | 4 + crates/oxc_codegen/Cargo.toml | 4 + .../printer => oxc_codegen/src}/context.rs | 0 .../src/printer => oxc_codegen/src}/gen.rs | 594 +++++++++--------- crates/oxc_codegen/src/lib.rs | 241 ++++++- .../printer => oxc_codegen/src}/operator.rs | 0 crates/oxc_minifier/Cargo.toml | 2 + crates/oxc_minifier/src/lib.rs | 20 +- crates/oxc_minifier/src/printer/mod.rs | 269 -------- crates/oxc_minifier/tests/mod.rs | 4 +- crates/oxc_minifier/tests/terser/mod.rs | 4 +- 12 files changed, 561 insertions(+), 583 deletions(-) rename crates/{oxc_minifier/src/printer => oxc_codegen/src}/context.rs (100%) rename crates/{oxc_minifier/src/printer => oxc_codegen/src}/gen.rs (71%) rename crates/{oxc_minifier/src/printer => oxc_codegen/src}/operator.rs (100%) delete mode 100644 crates/oxc_minifier/src/printer/mod.rs diff --git a/.github/labeler.yml b/.github/labeler.yml index a6543e09875ede..cb9c657cd0b08c 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -10,7 +10,7 @@ A-minifier: 'crates/oxc_minifier/**/*' A-parser: 'crates/oxc_parser/**/*' -A-printer: 'crates/oxc_minifier/src/printer/**/*' +A-codegen: 'crates/oxc_codegen/**/*' A-semantic: 'crates/oxc_semantic/**/*' diff --git a/Cargo.lock b/Cargo.lock index 38603aff7b56fd..69634127ae7fee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1517,10 +1517,13 @@ dependencies = [ name = "oxc_codegen" version = "0.2.0" dependencies = [ + "bitflags 2.4.0", + "num-bigint", "oxc_allocator", "oxc_ast", "oxc_parser", "oxc_span", + "oxc_syntax", ] [[package]] @@ -1659,6 +1662,7 @@ dependencies = [ "num-traits", "oxc_allocator", "oxc_ast", + "oxc_codegen", "oxc_index", "oxc_parser", "oxc_semantic", diff --git a/crates/oxc_codegen/Cargo.toml b/crates/oxc_codegen/Cargo.toml index 5d3545d8e70117..eb098fd64ae834 100644 --- a/crates/oxc_codegen/Cargo.toml +++ b/crates/oxc_codegen/Cargo.toml @@ -19,6 +19,10 @@ doctest = false oxc_ast = { workspace = true } oxc_span = { workspace = true } oxc_allocator = { workspace = true } +oxc_syntax = { workspace = true } + +bitflags = { workspace = true } +num-bigint = { workspace = true } [dev-dependencies] oxc_parser = { workspace = true } diff --git a/crates/oxc_minifier/src/printer/context.rs b/crates/oxc_codegen/src/context.rs similarity index 100% rename from crates/oxc_minifier/src/printer/context.rs rename to crates/oxc_codegen/src/context.rs diff --git a/crates/oxc_minifier/src/printer/gen.rs b/crates/oxc_codegen/src/gen.rs similarity index 71% rename from crates/oxc_minifier/src/printer/gen.rs rename to crates/oxc_codegen/src/gen.rs index 47d55fa1c5ab76..9ef7c5d5adb27b 100644 --- a/crates/oxc_minifier/src/printer/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1,45 +1,42 @@ use oxc_allocator::{Box, Vec}; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; -use oxc_ast::precedence; use oxc_syntax::{ - operator::{ - AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator, - }, + operator::{BinaryOperator, LogicalOperator, UnaryOperator}, precedence::{GetPrecedence, Precedence}, NumberBase, }; -use super::{Context, Operator, Printer, Separator}; +use super::{Codegen, Context, Operator, Separator}; -pub trait Gen { - fn gen(&self, p: &mut Printer, ctx: Context) {} +pub trait Gen { + fn gen(&self, _p: &mut Codegen<{ MINIFY }>, _ctx: Context) {} } -pub trait GenExpr { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) {} +pub trait GenExpr { + fn gen_expr(&self, _p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, _ctx: Context) {} } -impl<'a, T> Gen for Box<'a, T> +impl<'a, const MINIFY: bool, T> Gen for Box<'a, T> where - T: Gen, + T: Gen, { - fn gen(&self, p: &mut Printer, ctx: Context) { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { (**self).gen(p, ctx); } } -impl<'a, T> GenExpr for Box<'a, T> +impl<'a, const MINIFY: bool, T> GenExpr for Box<'a, T> where - T: GenExpr, + T: GenExpr, { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { (**self).gen_expr(p, precedence, ctx); } } -impl<'a> Gen for Program<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Program<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if let Some(hashbang) = &self.hashbang { hashbang.gen(p, ctx); } @@ -53,15 +50,15 @@ impl<'a> Gen for Program<'a> { } } -impl Gen for Hashbang { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for Hashbang { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"#!"); p.print_str(self.value.as_bytes()); } } -impl Gen for Directive { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for Directive { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b'"'); p.print_str(self.directive.as_bytes()); p.print(b'"'); @@ -69,8 +66,8 @@ impl Gen for Directive { } } -impl<'a> Gen for Statement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Statement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::BlockStatement(stmt) => stmt.gen(p, ctx), Self::BreakStatement(stmt) => stmt.gen(p, ctx), @@ -96,8 +93,8 @@ impl<'a> Gen for Statement<'a> { } } -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Option> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Some(stmt) => stmt.gen(p, ctx), None => p.print(b';'), @@ -105,8 +102,8 @@ impl<'a> Gen for Option> { } } -impl<'a> Gen for ExpressionStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ExpressionStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.start_of_stmt = p.code_len(); self.expression.gen_expr(p, Precedence::lowest(), Context::default()); if self.expression.is_specific_id("let") { @@ -117,13 +114,17 @@ impl<'a> Gen for ExpressionStatement<'a> { } } -impl<'a> Gen for IfStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for IfStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { print_if(self, p, ctx); } } -fn print_if(if_stmt: &IfStatement<'_>, p: &mut Printer, ctx: Context) { +fn print_if( + if_stmt: &IfStatement<'_>, + p: &mut Codegen<{ MINIFY }>, + ctx: Context, +) { p.print_str(b"if"); p.print(b'('); if_stmt.test.gen_expr(p, Precedence::lowest(), Context::default()); @@ -184,17 +185,16 @@ fn wrap_to_avoid_ambiguous_else(stmt: &Statement) -> bool { _ => return false, } } - false } -impl<'a> Gen for BlockStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for BlockStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_block1(self, ctx); } } -impl<'a> Gen for ForStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ForStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"for"); p.print(b'('); @@ -226,8 +226,8 @@ impl<'a> Gen for ForStatement<'a> { } } -impl<'a> Gen for ForInStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ForInStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"for"); p.print(b'('); self.left.gen(p, ctx); @@ -240,8 +240,8 @@ impl<'a> Gen for ForInStatement<'a> { } } -impl<'a> Gen for ForOfStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ForOfStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"for"); if self.r#await { p.print_str(b" await"); @@ -257,8 +257,8 @@ impl<'a> Gen for ForOfStatement<'a> { } } -impl<'a> Gen for ForStatementLeft<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ForStatementLeft<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match &self { ForStatementLeft::UsingDeclaration(var) => var.gen(p, ctx), ForStatementLeft::VariableDeclaration(var) => var.gen(p, ctx), @@ -267,8 +267,8 @@ impl<'a> Gen for ForStatementLeft<'a> { } } -impl<'a> Gen for WhileStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for WhileStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"while"); p.print(b'('); self.test.gen_expr(p, Precedence::lowest(), Context::default()); @@ -277,8 +277,8 @@ impl<'a> Gen for WhileStatement<'a> { } } -impl<'a> Gen for DoWhileStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for DoWhileStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"do"); p.print(b' '); if let Statement::BlockStatement(block) = &self.body { @@ -295,14 +295,14 @@ impl<'a> Gen for DoWhileStatement<'a> { } } -impl Gen for EmptyStatement { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for EmptyStatement { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b';'); } } -impl Gen for ContinueStatement { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for ContinueStatement { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"continue"); if let Some(label) = &self.label { p.print(b' '); @@ -312,8 +312,8 @@ impl Gen for ContinueStatement { } } -impl Gen for BreakStatement { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for BreakStatement { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"break"); if let Some(label) = &self.label { p.print(b' '); @@ -323,8 +323,8 @@ impl Gen for BreakStatement { } } -impl<'a> Gen for SwitchStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for SwitchStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"switch"); p.print(b'('); self.discriminant.gen_expr(p, Precedence::lowest(), Context::default()); @@ -338,8 +338,8 @@ impl<'a> Gen for SwitchStatement<'a> { } } -impl<'a> Gen for SwitchCase<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for SwitchCase<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_semicolon_if_needed(); match &self.test { Some(test) => { @@ -357,8 +357,8 @@ impl<'a> Gen for SwitchCase<'a> { } } -impl<'a> Gen for ReturnStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ReturnStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"return"); if let Some(arg) = &self.argument { p.print(b' '); @@ -368,16 +368,16 @@ impl<'a> Gen for ReturnStatement<'a> { } } -impl<'a> Gen for LabeledStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for LabeledStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.label.gen(p, ctx); p.print_colon(); self.body.gen(p, ctx); } } -impl<'a> Gen for TryStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for TryStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"try"); p.print_block1(&self.block, ctx); if let Some(handler) = &self.handler { @@ -396,8 +396,8 @@ impl<'a> Gen for TryStatement<'a> { } } -impl<'a> Gen for ThrowStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ThrowStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"throw"); p.print(b' '); self.argument.gen_expr(p, Precedence::lowest(), Context::default()); @@ -405,8 +405,8 @@ impl<'a> Gen for ThrowStatement<'a> { } } -impl<'a> Gen for WithStatement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for WithStatement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"with"); p.print(b'('); self.object.gen_expr(p, Precedence::lowest(), Context::default()); @@ -415,15 +415,15 @@ impl<'a> Gen for WithStatement<'a> { } } -impl Gen for DebuggerStatement { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for DebuggerStatement { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"debugger"); p.print_semicolon_after_statement(); } } -impl<'a> Gen for ModuleDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ModuleDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::ImportDeclaration(decl) => decl.gen(p, ctx), Self::ExportAllDeclaration(decl) => decl.gen(p, ctx), @@ -434,8 +434,8 @@ impl<'a> Gen for ModuleDeclaration<'a> { } } -impl<'a> Gen for Declaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Declaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::VariableDeclaration(stmt) => { stmt.gen(p, ctx); @@ -455,8 +455,8 @@ impl<'a> Gen for Declaration<'a> { } } -impl<'a> Gen for VariableDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for VariableDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(match self.kind { VariableDeclarationKind::Const => b"const", VariableDeclarationKind::Let => b"let", @@ -466,8 +466,8 @@ impl<'a> Gen for VariableDeclaration<'a> { p.print_list(&self.declarations, ctx); } } -impl<'a> Gen for UsingDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for UsingDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if self.is_await { p.print_str(b"await"); p.print(b' '); @@ -480,8 +480,8 @@ impl<'a> Gen for UsingDeclaration<'a> { } } -impl<'a> Gen for VariableDeclarator<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for VariableDeclarator<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.id.gen(p, ctx); if let Some(init) = &self.init { p.print_equal(); @@ -490,8 +490,8 @@ impl<'a> Gen for VariableDeclarator<'a> { } } -impl<'a> Gen for Function<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Function<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { let n = p.code_len(); let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n); p.wrap(wrap, |p| { @@ -519,8 +519,8 @@ impl<'a> Gen for Function<'a> { } } -impl<'a> Gen for FunctionBody<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for FunctionBody<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'{'); for directive in &self.directives { directive.gen(p, ctx); @@ -540,15 +540,15 @@ impl<'a> Gen for FunctionBody<'a> { } } -impl<'a> Gen for FormalParameter<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for FormalParameter<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.decorators.gen(p, ctx); self.pattern.gen(p, ctx); } } -impl<'a> Gen for FormalParameters<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for FormalParameters<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_list(&self.items, ctx); if let Some(rest) = &self.rest { if !self.items.is_empty() { @@ -559,8 +559,8 @@ impl<'a> Gen for FormalParameters<'a> { } } -impl<'a> Gen for ImportDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ImportDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"import "); if self.specifiers.is_empty() { p.print(b'\''); @@ -634,8 +634,8 @@ impl<'a> Gen for ImportDeclaration<'a> { } } -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Option> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if let Some(assertions) = &self { p.print_str(b"assert"); p.print_block(assertions, Separator::Comma, ctx); @@ -643,8 +643,8 @@ impl<'a> Gen for Option> { } } -impl Gen for ImportAttribute { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for ImportAttribute { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match &self.key { ImportAttributeKey::Identifier(identifier) => { p.print_str(identifier.name.as_bytes()); @@ -656,8 +656,8 @@ impl Gen for ImportAttribute { } } -impl<'a> Gen for ExportNamedDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ExportNamedDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"export "); match &self.declaration { Some(decl) => decl.gen(p, ctx), @@ -677,8 +677,8 @@ impl<'a> Gen for ExportNamedDeclaration<'a> { } } -impl Gen for ExportSpecifier { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for ExportSpecifier { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.local.gen(p, ctx); if self.local.name() != self.exported.name() { p.print_str(b" as "); @@ -687,8 +687,8 @@ impl Gen for ExportSpecifier { } } -impl Gen for ModuleExportName { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for ModuleExportName { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Identifier(identifier) => { p.print_str(identifier.name.as_bytes()); @@ -698,8 +698,8 @@ impl Gen for ModuleExportName { } } -impl<'a> Gen for ExportAllDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ExportAllDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"export"); p.print(b'*'); @@ -716,14 +716,14 @@ impl<'a> Gen for ExportAllDeclaration<'a> { } } -impl<'a> Gen for ExportDefaultDeclaration<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ExportDefaultDeclaration<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"export default "); self.declaration.gen(p, ctx); } } -impl<'a> Gen for ExportDefaultDeclarationKind<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ExportDefaultDeclarationKind<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Expression(expr) => { p.start_of_default_export = p.code_len(); @@ -737,8 +737,8 @@ impl<'a> Gen for ExportDefaultDeclarationKind<'a> { } } -impl<'a> GenExpr for Expression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for Expression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { match self { Self::BooleanLiteral(lit) => lit.gen(p, ctx), Self::NullLiteral(lit) => lit.gen(p, ctx), @@ -782,54 +782,54 @@ impl<'a> GenExpr for Expression<'a> { } } -impl Gen for IdentifierReference { - fn gen(&self, p: &mut Printer, ctx: Context) { - if let Some(mangler) = &p.mangler { - if let Some(reference_id) = self.reference_id.clone().into_inner() { - if let Some(name) = mangler.get_reference_name(reference_id) { - p.print_str(name.clone().as_bytes()); - return; - } - } - } +impl Gen for IdentifierReference { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { + // if let Some(mangler) = &p.mangler { + // if let Some(reference_id) = self.reference_id.clone().into_inner() { + // if let Some(name) = mangler.get_reference_name(reference_id) { + // p.print_str(name.clone().as_bytes()); + // return; + // } + // } + // } p.print_str(self.name.as_bytes()); } } -impl Gen for IdentifierName { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for IdentifierName { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(self.name.as_bytes()); } } -impl Gen for BindingIdentifier { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for BindingIdentifier { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_symbol(self.symbol_id.clone().into_inner(), &self.name); } } -impl Gen for LabelIdentifier { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for LabelIdentifier { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(self.name.as_bytes()); } } -impl Gen for BooleanLiteral { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for BooleanLiteral { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(self.as_str().as_bytes()); } } -impl Gen for NullLiteral { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for NullLiteral { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_space_before_identifier(); p.print_str(b"null"); } } -impl<'a> Gen for NumberLiteral<'a> { +impl<'a, const MINIFY: bool> Gen for NumberLiteral<'a> { #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] - fn gen(&self, p: &mut Printer, ctx: Context) { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_space_before_identifier(); let abs_value = self.value.abs(); @@ -869,7 +869,7 @@ impl<'a> Gen for NumberLiteral<'a> { } // TODO: refactor this with less allocations -fn print_non_negative_float(value: f64, p: &Printer) -> String { +fn print_non_negative_float(value: f64, _p: &Codegen<{ MINIFY }>) -> String { let mut result = value.to_string(); let chars = result.as_bytes(); let len = chars.len(); @@ -923,8 +923,8 @@ fn print_non_negative_float(value: f64, p: &Printer) -> String { result } -impl Gen for BigintLiteral { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for BigintLiteral { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { use num_bigint::Sign; if self.value.sign() == Sign::Minus { @@ -935,8 +935,8 @@ impl Gen for BigintLiteral { } } -impl Gen for RegExpLiteral { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for RegExpLiteral { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { let last = p.peek_nth(0); // Avoid forming a single-line comment or " Gen for StringLiteral { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b'\''); for c in self.value.chars() { p.print_str(c.escape_default().to_string().as_bytes()); @@ -963,15 +963,15 @@ impl Gen for StringLiteral { } } -impl Gen for ThisExpression { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for ThisExpression { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_space_before_identifier(); p.print_str(b"this"); } } -impl<'a> GenExpr for MemberExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for MemberExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > self.precedence(), |p| match self { Self::ComputedMemberExpression(expr) => { expr.gen_expr(p, self.precedence(), ctx.and_in(true)); @@ -982,8 +982,8 @@ impl<'a> GenExpr for MemberExpression<'a> { } } -impl<'a> GenExpr for ComputedMemberExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for ComputedMemberExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) { self.object.gen_expr(p, Precedence::Postfix, ctx); if self.optional { p.print_str(b"?."); @@ -994,8 +994,8 @@ impl<'a> GenExpr for ComputedMemberExpression<'a> { } } -impl<'a> GenExpr for StaticMemberExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for StaticMemberExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) { self.object.gen_expr(p, Precedence::Postfix, ctx); if self.optional { p.print(b'?'); @@ -1008,8 +1008,8 @@ impl<'a> GenExpr for StaticMemberExpression<'a> { } } -impl<'a> GenExpr for PrivateFieldExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for PrivateFieldExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) { self.object.gen_expr(p, Precedence::Postfix, ctx); if self.optional { p.print_str(b"?"); @@ -1019,8 +1019,8 @@ impl<'a> GenExpr for PrivateFieldExpression<'a> { } } -impl<'a> GenExpr for CallExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for CallExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > self.precedence(), |p| { self.callee.gen_expr(p, self.precedence(), ctx); if self.optional { @@ -1033,8 +1033,8 @@ impl<'a> GenExpr for CallExpression<'a> { } } -impl<'a> Gen for Argument<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Argument<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::SpreadElement(elem) => elem.gen(p, ctx), Self::Expression(elem) => elem.gen_expr(p, Precedence::Assign, Context::default()), @@ -1042,8 +1042,8 @@ impl<'a> Gen for Argument<'a> { } } -impl<'a> Gen for ArrayExpressionElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ArrayExpressionElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Expression(expr) => expr.gen_expr(p, Precedence::Assign, Context::default()), Self::SpreadElement(elem) => elem.gen(p, ctx), @@ -1052,15 +1052,15 @@ impl<'a> Gen for ArrayExpressionElement<'a> { } } -impl<'a> Gen for SpreadElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for SpreadElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_ellipsis(); self.argument.gen_expr(p, Precedence::Assign, Context::default()); } } -impl<'a> Gen for ArrayExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ArrayExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'['); p.print_list(&self.elements, ctx); if self.trailing_comma.is_some() { @@ -1070,8 +1070,8 @@ impl<'a> Gen for ArrayExpression<'a> { } } -impl<'a> GenExpr for ObjectExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for ObjectExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) { let n = p.code_len(); p.wrap(p.start_of_stmt == n || p.start_of_arrow_expr == n, |p| { p.print(b'{'); @@ -1086,8 +1086,8 @@ impl<'a> GenExpr for ObjectExpression<'a> { } } -impl<'a> Gen for ObjectPropertyKind<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ObjectPropertyKind<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::ObjectProperty(prop) => prop.gen(p, ctx), Self::SpreadProperty(elem) => elem.gen(p, ctx), @@ -1095,8 +1095,8 @@ impl<'a> Gen for ObjectPropertyKind<'a> { } } -impl<'a> Gen for ObjectProperty<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ObjectProperty<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if let Expression::FunctionExpression(func) = &self.value { let is_accessor = match &self.kind { PropertyKind::Init => false, @@ -1144,8 +1144,8 @@ impl<'a> Gen for ObjectProperty<'a> { } } -impl<'a> Gen for PropertyKey<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for PropertyKey<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Identifier(ident) => ident.gen(p, ctx), Self::PrivateIdentifier(ident) => ident.gen(p, ctx), @@ -1154,8 +1154,8 @@ impl<'a> Gen for PropertyKey<'a> { } } -impl<'a> GenExpr for ArrowExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for ArrowExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > Precedence::Assign, |p| { if self.r#async { p.print_str(b"async"); @@ -1183,8 +1183,8 @@ impl<'a> GenExpr for ArrowExpression<'a> { } } -impl<'a> GenExpr for YieldExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for YieldExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence >= self.precedence(), |p| { p.print_str(b"yield"); if self.delegate { @@ -1201,8 +1201,8 @@ impl<'a> GenExpr for YieldExpression<'a> { } } -impl<'a> GenExpr for UpdateExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for UpdateExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { let operator = self.operator.as_str().as_bytes(); p.wrap(precedence > self.precedence(), |p| { if self.prefix { @@ -1221,8 +1221,8 @@ impl<'a> GenExpr for UpdateExpression<'a> { } } -impl<'a> GenExpr for UnaryExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for UnaryExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > self.precedence() || precedence == Precedence::Exponential, |p| { let operator = self.operator.as_str().as_bytes(); if self.operator.is_keyword() { @@ -1239,8 +1239,8 @@ impl<'a> GenExpr for UnaryExpression<'a> { } } -impl<'a> GenExpr for BinaryExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for BinaryExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { let wrap_in = self.operator == BinaryOperator::In && !ctx.has_in(); let wrap = precedence > self.precedence() || wrap_in; p.wrap(wrap, |p| { @@ -1254,8 +1254,8 @@ impl<'a> GenExpr for BinaryExpression<'a> { } } -impl Gen for BinaryOperator { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for BinaryOperator { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { let operator = self.as_str().as_bytes(); if self.is_keyword() { p.print_str(operator); @@ -1270,8 +1270,8 @@ impl Gen for BinaryOperator { } } -impl<'a> Gen for PrivateInExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for PrivateInExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.left.gen(p, ctx); p.print(b' '); p.print_str(b"in"); @@ -1280,8 +1280,8 @@ impl<'a> Gen for PrivateInExpression<'a> { } } -impl<'a> GenExpr for LogicalExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for LogicalExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { // Logical expressions and coalesce expressions cannot be mixed (Syntax Error). let mixed = matches!( (precedence, self.precedence()), @@ -1290,7 +1290,7 @@ impl<'a> GenExpr for LogicalExpression<'a> { p.wrap(mixed || (precedence > self.precedence()), |p| { self.left.gen_expr(p, self.precedence(), ctx); p.print_str(self.operator.as_str().as_bytes()); - let precedence = match self.operator { + let _precedence = match self.operator { LogicalOperator::And | LogicalOperator::Coalesce => Precedence::BitwiseOr, LogicalOperator::Or => Precedence::LogicalAnd, }; @@ -1299,8 +1299,8 @@ impl<'a> GenExpr for LogicalExpression<'a> { } } -impl<'a> GenExpr for ConditionalExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for ConditionalExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { let wrap = precedence > self.precedence(); p.wrap(wrap, |p| { self.test.gen_expr(p, self.precedence(), ctx); @@ -1312,8 +1312,8 @@ impl<'a> GenExpr for ConditionalExpression<'a> { } } -impl<'a> GenExpr for AssignmentExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for AssignmentExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { // Destructuring assignment let n = p.code_len(); let wrap = (p.start_of_stmt == n || p.start_of_arrow_expr == n) @@ -1331,8 +1331,8 @@ impl<'a> GenExpr for AssignmentExpression<'a> { } } -impl<'a> Gen for AssignmentTarget<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTarget<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::SimpleAssignmentTarget(target) => { target.gen_expr(p, Precedence::Assign, Context::default()); @@ -1342,8 +1342,8 @@ impl<'a> Gen for AssignmentTarget<'a> { } } -impl<'a> GenExpr for SimpleAssignmentTarget<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for SimpleAssignmentTarget<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { match self { Self::AssignmentTargetIdentifier(ident) => ident.gen(p, ctx), Self::MemberAssignmentTarget(member_expr) => { @@ -1354,8 +1354,8 @@ impl<'a> GenExpr for SimpleAssignmentTarget<'a> { } } -impl<'a> Gen for AssignmentTargetPattern<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetPattern<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::ArrayAssignmentTarget(target) => target.gen(p, ctx), Self::ObjectAssignmentTarget(target) => target.gen(p, ctx), @@ -1363,8 +1363,8 @@ impl<'a> Gen for AssignmentTargetPattern<'a> { } } -impl<'a> Gen for ArrayAssignmentTarget<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ArrayAssignmentTarget<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'['); p.print_list(&self.elements, ctx); if let Some(target) = &self.rest { @@ -1379,16 +1379,16 @@ impl<'a> Gen for ArrayAssignmentTarget<'a> { } } -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Option> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if let Some(arg) = self { arg.gen(p, ctx); } } } -impl<'a> Gen for ObjectAssignmentTarget<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ObjectAssignmentTarget<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'{'); p.print_list(&self.properties, ctx); if let Some(target) = &self.rest { @@ -1402,8 +1402,8 @@ impl<'a> Gen for ObjectAssignmentTarget<'a> { } } -impl<'a> Gen for AssignmentTargetMaybeDefault<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetMaybeDefault<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::AssignmentTarget(target) => target.gen(p, ctx), Self::AssignmentTargetWithDefault(target) => target.gen(p, ctx), @@ -1411,16 +1411,16 @@ impl<'a> Gen for AssignmentTargetMaybeDefault<'a> { } } -impl<'a> Gen for AssignmentTargetWithDefault<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetWithDefault<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.binding.gen(p, ctx); p.print_equal(); self.init.gen_expr(p, Precedence::Assign, Context::default()); } } -impl<'a> Gen for AssignmentTargetProperty<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetProperty<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::AssignmentTargetPropertyIdentifier(ident) => ident.gen(p, ctx), Self::AssignmentTargetPropertyProperty(prop) => prop.gen(p, ctx), @@ -1428,8 +1428,8 @@ impl<'a> Gen for AssignmentTargetProperty<'a> { } } -impl<'a> Gen for AssignmentTargetPropertyIdentifier<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetPropertyIdentifier<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.binding.gen(p, ctx); if let Some(expr) = &self.init { p.print_equal(); @@ -1438,8 +1438,8 @@ impl<'a> Gen for AssignmentTargetPropertyIdentifier<'a> { } } -impl<'a> Gen for AssignmentTargetPropertyProperty<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentTargetPropertyProperty<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match &self.name { PropertyKey::Identifier(ident) => { ident.gen(p, ctx); @@ -1458,16 +1458,16 @@ impl<'a> Gen for AssignmentTargetPropertyProperty<'a> { } } -impl<'a> GenExpr for SequenceExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for SequenceExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, _ctx: Context) { p.wrap(precedence > self.precedence(), |p| { p.print_expressions(&self.expressions, Precedence::Assign, Context::default()); }); } } -impl<'a> Gen for ImportExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ImportExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"import("); self.source.gen_expr(p, Precedence::Assign, Context::default()); if !self.arguments.is_empty() { @@ -1478,8 +1478,8 @@ impl<'a> Gen for ImportExpression<'a> { } } -impl<'a> Gen for TemplateLiteral<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for TemplateLiteral<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b'`'); let mut expressions = self.expressions.iter(); @@ -1497,21 +1497,21 @@ impl<'a> Gen for TemplateLiteral<'a> { } } -impl<'a> Gen for TaggedTemplateExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for TaggedTemplateExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.tag.gen_expr(p, Precedence::Call, Context::default()); self.quasi.gen(p, ctx); } } -impl Gen for Super { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for Super { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"super"); } } -impl<'a> GenExpr for AwaitExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for AwaitExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > self.precedence(), |p| { p.print_str(b"await "); self.argument.gen_expr(p, self.precedence(), ctx); @@ -1519,8 +1519,8 @@ impl<'a> GenExpr for AwaitExpression<'a> { } } -impl<'a> GenExpr for ChainExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for ChainExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { match &self.expression { ChainElement::CallExpression(expr) => expr.gen_expr(p, precedence, ctx), ChainElement::MemberExpression(expr) => expr.gen_expr(p, precedence, ctx), @@ -1528,8 +1528,8 @@ impl<'a> GenExpr for ChainExpression<'a> { } } -impl<'a> GenExpr for NewExpression<'a> { - fn gen_expr(&self, p: &mut Printer, precedence: Precedence, ctx: Context) { +impl<'a, const MINIFY: bool> GenExpr for NewExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > self.precedence(), |p| { p.print_str(b"new "); self.callee.gen_expr(p, self.precedence(), ctx); @@ -1540,16 +1540,16 @@ impl<'a> GenExpr for NewExpression<'a> { } } -impl Gen for MetaProperty { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for MetaProperty { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.meta.gen(p, ctx); p.print(b'.'); self.property.gen(p, ctx); } } -impl<'a> Gen for Class<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Class<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { let n = p.code_len(); let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n); p.wrap(wrap, |p| { @@ -1580,8 +1580,8 @@ impl<'a> Gen for Class<'a> { } } -impl<'a> Gen for ClassElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ClassElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::StaticBlock(elem) => elem.gen(p, ctx), Self::MethodDefinition(elem) => elem.gen(p, ctx), @@ -1592,14 +1592,14 @@ impl<'a> Gen for ClassElement<'a> { } } -impl Gen for JSXIdentifier { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for JSXIdentifier { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(self.name.as_bytes()); } } -impl<'a> Gen for JSXMemberExpressionObject<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXMemberExpressionObject<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Identifier(ident) => ident.gen(p, ctx), Self::MemberExpression(member_expr) => member_expr.gen(p, ctx), @@ -1607,16 +1607,16 @@ impl<'a> Gen for JSXMemberExpressionObject<'a> { } } -impl<'a> Gen for JSXMemberExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXMemberExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.object.gen(p, ctx); p.print(b'.'); self.property.gen(p, ctx); } } -impl<'a> Gen for JSXElementName<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXElementName<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Identifier(identifier) => identifier.gen(p, ctx), Self::NamespacedName(namespaced_name) => namespaced_name.gen(p, ctx), @@ -1625,16 +1625,16 @@ impl<'a> Gen for JSXElementName<'a> { } } -impl Gen for JSXNamespacedName { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for JSXNamespacedName { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.namespace.gen(p, ctx); p.print(b'.'); self.property.gen(p, ctx); } } -impl<'a> Gen for JSXAttributeName<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXAttributeName<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Identifier(ident) => ident.gen(p, ctx), Self::NamespacedName(namespaced_name) => namespaced_name.gen(p, ctx), @@ -1642,8 +1642,8 @@ impl<'a> Gen for JSXAttributeName<'a> { } } -impl<'a> Gen for JSXAttribute<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXAttribute<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.name.gen(p, ctx); p.print(b'='); if let Some(value) = &self.value { @@ -1652,12 +1652,12 @@ impl<'a> Gen for JSXAttribute<'a> { } } -impl Gen for JSXEmptyExpression { - fn gen(&self, _: &mut Printer, ctx: Context) {} +impl Gen for JSXEmptyExpression { + fn gen(&self, _: &mut Codegen<{ MINIFY }>, _ctx: Context) {} } -impl<'a> Gen for JSXExpression<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXExpression<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Expression(expr) => expr.gen_expr(p, Precedence::lowest(), Context::default()), Self::EmptyExpression(expr) => expr.gen(p, ctx), @@ -1665,16 +1665,16 @@ impl<'a> Gen for JSXExpression<'a> { } } -impl<'a> Gen for JSXExpressionContainer<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXExpressionContainer<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'{'); self.expression.gen(p, ctx); p.print(b'}'); } } -impl<'a> Gen for JSXAttributeValue<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXAttributeValue<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Fragment(fragment) => fragment.gen(p, ctx), Self::Element(el) => el.gen(p, ctx), @@ -1684,14 +1684,14 @@ impl<'a> Gen for JSXAttributeValue<'a> { } } -impl<'a> Gen for JSXSpreadAttribute<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXSpreadAttribute<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { self.argument.gen_expr(p, Precedence::lowest(), Context::default()); } } -impl<'a> Gen for JSXAttributeItem<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXAttributeItem<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Attribute(attr) => attr.gen(p, ctx), Self::SpreadAttribute(spread_attr) => spread_attr.gen(p, ctx), @@ -1699,8 +1699,8 @@ impl<'a> Gen for JSXAttributeItem<'a> { } } -impl<'a> Gen for JSXOpeningElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXOpeningElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"<"); self.name.gen(p, ctx); for attr in &self.attributes { @@ -1714,16 +1714,16 @@ impl<'a> Gen for JSXOpeningElement<'a> { } } -impl<'a> Gen for JSXClosingElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXClosingElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"'); } } -impl<'a> Gen for JSXElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.opening_element.gen(p, ctx); for child in &self.children { child.gen(p, ctx); @@ -1734,33 +1734,33 @@ impl<'a> Gen for JSXElement<'a> { } } -impl Gen for JSXOpeningFragment { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for JSXOpeningFragment { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"<>"); } } -impl Gen for JSXClosingFragment { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for JSXClosingFragment { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b""); } } -impl Gen for JSXText { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for JSXText { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(self.value.as_bytes()); } } -impl<'a> Gen for JSXSpreadChild<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXSpreadChild<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"..."); self.expression.gen_expr(p, Precedence::lowest(), Context::default()); } } -impl<'a> Gen for JSXChild<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXChild<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::Fragment(fragment) => fragment.gen(p, ctx), Self::Element(el) => el.gen(p, ctx), @@ -1773,8 +1773,8 @@ impl<'a> Gen for JSXChild<'a> { } } -impl<'a> Gen for JSXFragment<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for JSXFragment<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.opening_fragment.gen(p, ctx); for child in &self.children { child.gen(p, ctx); @@ -1783,8 +1783,8 @@ impl<'a> Gen for JSXFragment<'a> { } } -impl<'a> Gen for StaticBlock<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for StaticBlock<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"static"); p.print(b'{'); for stmt in &self.body { @@ -1796,8 +1796,8 @@ impl<'a> Gen for StaticBlock<'a> { } } -impl<'a> Gen for MethodDefinition<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for MethodDefinition<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.decorators.gen(p, ctx); if self.r#static { @@ -1834,8 +1834,8 @@ impl<'a> Gen for MethodDefinition<'a> { } } -impl<'a> Gen for PropertyDefinition<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for PropertyDefinition<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.decorators.gen(p, ctx); if self.r#static { p.print_str(b"static "); @@ -1854,8 +1854,8 @@ impl<'a> Gen for PropertyDefinition<'a> { } } -impl<'a> Gen for AccessorProperty<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AccessorProperty<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if self.r#static { p.print_str(b"static "); } @@ -1874,15 +1874,15 @@ impl<'a> Gen for AccessorProperty<'a> { } } -impl Gen for PrivateIdentifier { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl Gen for PrivateIdentifier { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b'#'); p.print_str(self.name.as_bytes()); } } -impl<'a> Gen for BindingPattern<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for BindingPattern<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match &self.kind { BindingPatternKind::BindingIdentifier(ident) => ident.gen(p, ctx), BindingPatternKind::ObjectPattern(pattern) => pattern.gen(p, ctx), @@ -1892,8 +1892,8 @@ impl<'a> Gen for BindingPattern<'a> { } } -impl<'a> Gen for ObjectPattern<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ObjectPattern<'a> { + fn gen(&self, p: &mut Codegen, ctx: Context) { p.print(b'{'); p.print_list(&self.properties, ctx); if let Some(rest) = &self.rest { @@ -1906,8 +1906,8 @@ impl<'a> Gen for ObjectPattern<'a> { } } -impl<'a> Gen for BindingProperty<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for BindingProperty<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { if self.computed { p.print(b'['); } @@ -1920,15 +1920,15 @@ impl<'a> Gen for BindingProperty<'a> { } } -impl<'a> Gen for RestElement<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for RestElement<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_ellipsis(); self.argument.gen(p, ctx); } } -impl<'a> Gen for ArrayPattern<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for ArrayPattern<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print(b'['); for (index, item) in self.elements.iter().enumerate() { if index != 0 { @@ -1948,16 +1948,16 @@ impl<'a> Gen for ArrayPattern<'a> { } } -impl<'a> Gen for AssignmentPattern<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for AssignmentPattern<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { self.left.gen(p, ctx); p.print_equal(); self.right.gen_expr(p, Precedence::Assign, Context::default()); } } -impl<'a> Gen for Vec<'a, Decorator<'a>> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Vec<'a, Decorator<'a>> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { for decorator in self { decorator.gen(p, ctx); p.print(b' '); @@ -1965,8 +1965,8 @@ impl<'a> Gen for Vec<'a, Decorator<'a>> { } } -impl<'a> Gen for Decorator<'a> { - fn gen(&self, p: &mut Printer, ctx: Context) { +impl<'a, const MINIFY: bool> Gen for Decorator<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print(b'@'); self.expression.gen_expr(p, Precedence::Assign, Context::default()); } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index b90df5a630460a..eeee50851a3a82 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -4,9 +4,32 @@ //! //! * whitespace removal //! * sourcemaps +//! +//! Code adapted from +//! * [esbuild](https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer.go) + +mod context; +mod gen; +mod operator; + +use std::str::from_utf8_unchecked; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; +use oxc_span::Atom; +use oxc_syntax::{ + identifier::is_identifier_part, + operator::{BinaryOperator, UnaryOperator, UpdateOperator}, + precedence::Precedence, + symbol::SymbolId, +}; + +use self::{ + context::Context, + gen::{Gen, GenExpr}, + operator::Operator, +}; +// use crate::mangler::Mangler; #[derive(Debug, Default, Clone, Copy)] pub struct CodegenOptions; @@ -15,8 +38,30 @@ pub struct Codegen { #[allow(unused)] options: CodegenOptions, + // mangler: Option, /// Output Code code: Vec, + + // states + prev_op_end: usize, + prev_reg_exp_end: usize, + need_space_before_dot: usize, + + /// For avoiding `;` if the previous statement ends with `}`. + needs_semicolon: bool, + + prev_op: Option, + + start_of_stmt: usize, + start_of_arrow_expr: usize, + start_of_default_export: usize, +} + +#[derive(Debug, Clone, Copy)] +pub enum Separator { + Comma, + Semicolon, + None, } impl Codegen { @@ -24,14 +69,206 @@ impl Codegen { // Initialize the output code buffer to reduce memory reallocation. // Minification will reduce by at least half of the original size. let capacity = if MINIFY { source_len / 2 } else { source_len }; - Self { options, code: Vec::with_capacity(capacity) } + Self { + options, + // mangler: None, + code: Vec::with_capacity(capacity), + needs_semicolon: false, + need_space_before_dot: 0, + prev_op_end: 0, + prev_reg_exp_end: 0, + prev_op: None, + start_of_stmt: 0, + start_of_arrow_expr: 0, + start_of_default_export: 0, + } } - pub fn build(self, _program: &Program<'_>) -> String { + // pub fn with_mangler(&mut self, mangler: Mangler) { + // self.mangler = Some(mangler); + // } + + pub fn build(mut self, program: &Program<'_>) -> String { + program.gen(&mut self, Context::default()); self.into_code() } fn into_code(self) -> String { unsafe { String::from_utf8_unchecked(self.code) } } + + fn code(&self) -> &Vec { + &self.code + } + + fn code_len(&self) -> usize { + self.code().len() + } + + /// Push a single character into the buffer + fn print(&mut self, ch: u8) { + self.code.push(ch); + } + + /// Push a string into the buffer + fn print_str(&mut self, s: &[u8]) { + self.code.extend_from_slice(s); + } + + fn print_semicolon(&mut self) { + self.print(b';'); + } + + fn print_comma(&mut self) { + self.print(b','); + } + + fn print_space_before_operator(&mut self, next: Operator) { + if self.prev_op_end != self.code.len() { + return; + } + let Some(prev) = self.prev_op else { return }; + // "+ + y" => "+ +y" + // "+ ++ y" => "+ ++y" + // "x + + y" => "x+ +y" + // "x ++ + y" => "x+++y" + // "x + ++ y" => "x+ ++y" + // "-- >" => "-- >" + // "< ! --" => " Option { + unsafe { from_utf8_unchecked(self.code()) }.chars().nth_back(n) + } + + fn print_semicolon_after_statement(&mut self) { + self.needs_semicolon = true; + } + + fn print_semicolon_if_needed(&mut self) { + if self.needs_semicolon { + self.print_semicolon(); + self.needs_semicolon = false; + } + } + + fn print_ellipsis(&mut self) { + self.print_str(b"..."); + } + + fn print_colon(&mut self) { + self.print(b':'); + } + + fn print_equal(&mut self) { + self.print(b'='); + } + + fn print_sequence>(&mut self, items: &[T], separator: Separator, ctx: Context) { + let len = items.len(); + for (index, item) in items.iter().enumerate() { + item.gen(self, ctx); + match separator { + Separator::Semicolon => self.print_semicolon(), + Separator::Comma => self.print(b','), + Separator::None => {} + } + if index != len - 1 {} + } + } + + // fn print_body(&mut self, stmt: &Statement<'_>, ctx: Context) { + // if let Statement::BlockStatement(block) = stmt { + // self.print_block1(block, ctx); + // } else { + // stmt.gen(self, ctx); + // } + // } + + fn print_block1(&mut self, stmt: &BlockStatement<'_>, ctx: Context) { + self.print(b'{'); + for item in &stmt.body { + self.print_semicolon_if_needed(); + item.gen(self, ctx); + } + self.needs_semicolon = false; + self.print(b'}'); + } + + fn print_block>(&mut self, items: &[T], separator: Separator, ctx: Context) { + self.print(b'{'); + self.print_sequence(items, separator, ctx); + self.print(b'}'); + } + + fn print_list>(&mut self, items: &[T], ctx: Context) { + for (index, item) in items.iter().enumerate() { + if index != 0 { + self.print_comma(); + } + item.gen(self, ctx); + } + } + + fn print_expressions>( + &mut self, + items: &[T], + precedence: Precedence, + ctx: Context, + ) { + for (index, item) in items.iter().enumerate() { + if index != 0 { + self.print_comma(); + } + item.gen_expr(self, precedence, ctx); + } + } + + fn print_symbol(&mut self, _symbol_id: Option, fallback: &Atom) { + // if let Some(mangler) = &self.mangler { + // if let Some(symbol_id) = symbol_id { + // let name = mangler.get_symbol_name(symbol_id); + // self.print_str(name.clone().as_bytes()); + // return; + // } + // } + self.print_str(fallback.as_bytes()); + } + + fn wrap(&mut self, wrap: bool, mut f: F) { + if wrap { + self.print(b'('); + } + f(self); + if wrap { + self.print(b')'); + } + } } diff --git a/crates/oxc_minifier/src/printer/operator.rs b/crates/oxc_codegen/src/operator.rs similarity index 100% rename from crates/oxc_minifier/src/printer/operator.rs rename to crates/oxc_codegen/src/operator.rs diff --git a/crates/oxc_minifier/Cargo.toml b/crates/oxc_minifier/Cargo.toml index c967fab6650cbf..cd97fbb3a7709e 100644 --- a/crates/oxc_minifier/Cargo.toml +++ b/crates/oxc_minifier/Cargo.toml @@ -23,6 +23,8 @@ oxc_ast = { workspace = true } oxc_semantic = { workspace = true } oxc_syntax = { workspace = true } oxc_index = { workspace = true } +oxc_codegen = { workspace = true } + bitflags = { workspace = true } num-bigint = { workspace = true } itertools = { workspace = true } diff --git a/crates/oxc_minifier/src/lib.rs b/crates/oxc_minifier/src/lib.rs index 03c636768284af..9740e6371013a0 100644 --- a/crates/oxc_minifier/src/lib.rs +++ b/crates/oxc_minifier/src/lib.rs @@ -2,28 +2,28 @@ mod compressor; mod mangler; -mod printer; use oxc_allocator::Allocator; +use oxc_codegen::Codegen; use oxc_parser::Parser; use oxc_span::SourceType; pub use crate::{ compressor::{CompressOptions, Compressor}, mangler::ManglerBuilder, - printer::{Printer, PrinterOptions}, }; +pub use oxc_codegen::CodegenOptions; #[derive(Debug, Clone, Copy)] pub struct MinifierOptions { pub mangle: bool, pub compress: CompressOptions, - pub print: PrinterOptions, + pub codegen: CodegenOptions, } impl Default for MinifierOptions { fn default() -> Self { - Self { mangle: true, compress: CompressOptions::default(), print: PrinterOptions } + Self { mangle: true, compress: CompressOptions::default(), codegen: CodegenOptions } } } @@ -45,11 +45,11 @@ impl<'a> Minifier<'a> { let program = allocator.alloc(ret.program); Compressor::new(&allocator, self.options.compress).build(program); - let mut printer = Printer::new(self.source_text.len(), self.options.print); - if self.options.mangle { - let mangler = ManglerBuilder.build(program); - printer.with_mangler(mangler); - } - printer.build(program) + let codegen = Codegen::::new(self.source_text.len(), self.options.codegen); + // if self.options.mangle { + // let mangler = ManglerBuilder.build(program); + // printer.with_mangler(mangler); + // } + codegen.build(program) } } diff --git a/crates/oxc_minifier/src/printer/mod.rs b/crates/oxc_minifier/src/printer/mod.rs deleted file mode 100644 index edcf8260611912..00000000000000 --- a/crates/oxc_minifier/src/printer/mod.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Printer with whitespace minification -//! code adapted from [esbuild](https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer.go) - -#![allow(unused)] - -mod context; -mod gen; -mod operator; - -use std::{rc::Rc, str::from_utf8_unchecked}; - -#[allow(clippy::wildcard_imports)] -use oxc_ast::ast::*; -use oxc_ast::precedence; -use oxc_semantic::{SymbolId, SymbolTable}; -use oxc_span::{Atom, Span}; -use oxc_syntax::{ - identifier::is_identifier_part, - operator::{ - AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator, - }, - precedence::Precedence, -}; - -use self::{ - context::Context, - gen::{Gen, GenExpr}, - operator::Operator, -}; -use crate::mangler::Mangler; - -#[derive(Debug, Default, Clone, Copy)] -pub struct PrinterOptions; - -pub struct Printer { - options: PrinterOptions, - - mangler: Option, - - /// Output Code - code: Vec, - - // states - prev_op_end: usize, - prev_reg_exp_end: usize, - need_space_before_dot: usize, - - /// For avoiding `;` if the previous statement ends with `}`. - needs_semicolon: bool, - - prev_op: Option, - - start_of_stmt: usize, - start_of_arrow_expr: usize, - start_of_default_export: usize, -} - -#[derive(Debug, Clone, Copy)] -pub enum Separator { - Comma, - Semicolon, - None, -} - -/// Codegen interface for pretty print or minification -impl Printer { - pub fn new(source_len: usize, options: PrinterOptions) -> Self { - // Initialize the output code buffer to reduce memory reallocation. - // Minification will reduce by at least half the original size, - // so in fact no reallocation should happen at all. - let capacity = source_len / 2; - Self { - options, - mangler: None, - code: Vec::with_capacity(capacity), - needs_semicolon: false, - need_space_before_dot: 0, - prev_op_end: 0, - prev_reg_exp_end: 0, - prev_op: None, - start_of_stmt: 0, - start_of_arrow_expr: 0, - start_of_default_export: 0, - } - } - - pub fn with_mangler(&mut self, mangler: Mangler) { - self.mangler = Some(mangler); - } - - pub fn build(mut self, program: &Program<'_>) -> String { - program.gen(&mut self, Context::default()); - self.into_code() - } - - fn into_code(self) -> String { - unsafe { String::from_utf8_unchecked(self.code) } - } - - fn code(&self) -> &Vec { - &self.code - } - - fn code_len(&self) -> usize { - self.code().len() - } - - /// Push a single character into the buffer - fn print(&mut self, ch: u8) { - self.code.push(ch); - } - - /// Push a string into the buffer - fn print_str(&mut self, s: &[u8]) { - self.code.extend_from_slice(s); - } - - fn print_semicolon(&mut self) { - self.print(b';'); - } - - fn print_comma(&mut self) { - self.print(b','); - } - - fn print_space_before_operator(&mut self, next: Operator) { - if self.prev_op_end != self.code.len() { - return; - } - let Some(prev) = self.prev_op else { return }; - // "+ + y" => "+ +y" - // "+ ++ y" => "+ ++y" - // "x + + y" => "x+ +y" - // "x ++ + y" => "x+++y" - // "x + ++ y" => "x+ ++y" - // "-- >" => "-- >" - // "< ! --" => " Option { - unsafe { from_utf8_unchecked(self.code()) }.chars().nth_back(n) - } - - fn print_semicolon_after_statement(&mut self) { - self.needs_semicolon = true; - } - - fn print_semicolon_if_needed(&mut self) { - if self.needs_semicolon { - self.print_semicolon(); - self.needs_semicolon = false; - } - } - - fn print_ellipsis(&mut self) { - self.print_str(b"..."); - } - - fn print_colon(&mut self) { - self.print(b':'); - } - - fn print_equal(&mut self) { - self.print(b'='); - } - - fn print_sequence(&mut self, items: &[T], separator: Separator, ctx: Context) { - let len = items.len(); - for (index, item) in items.iter().enumerate() { - item.gen(self, ctx); - match separator { - Separator::Semicolon => self.print_semicolon(), - Separator::Comma => self.print(b','), - Separator::None => {} - } - if index != len - 1 {} - } - } - - fn print_body(&mut self, stmt: &Statement<'_>, ctx: Context) { - if let Statement::BlockStatement(block) = stmt { - self.print_block1(block, ctx); - } else { - stmt.gen(self, ctx); - } - } - - fn print_block1(&mut self, stmt: &BlockStatement<'_>, ctx: Context) { - self.print(b'{'); - for item in &stmt.body { - self.print_semicolon_if_needed(); - item.gen(self, ctx); - } - self.needs_semicolon = false; - self.print(b'}'); - } - - fn print_block(&mut self, items: &[T], separator: Separator, ctx: Context) { - self.print(b'{'); - self.print_sequence(items, separator, ctx); - self.print(b'}'); - } - - fn print_list(&mut self, items: &[T], ctx: Context) { - for (index, item) in items.iter().enumerate() { - if index != 0 { - self.print_comma(); - } - item.gen(self, ctx); - } - } - - fn print_expressions(&mut self, items: &[T], precedence: Precedence, ctx: Context) { - for (index, item) in items.iter().enumerate() { - if index != 0 { - self.print_comma(); - } - item.gen_expr(self, precedence, ctx); - } - } - - fn print_symbol(&mut self, symbol_id: Option, fallback: &Atom) { - if let Some(mangler) = &self.mangler { - if let Some(symbol_id) = symbol_id { - let name = mangler.get_symbol_name(symbol_id); - self.print_str(name.clone().as_bytes()); - return; - } - } - self.print_str(fallback.as_bytes()); - } - - fn wrap(&mut self, wrap: bool, mut f: F) { - if wrap { - self.print(b'('); - } - f(self); - if wrap { - self.print(b')'); - } - } -} diff --git a/crates/oxc_minifier/tests/mod.rs b/crates/oxc_minifier/tests/mod.rs index ae52b12496b175..5df0e47b7cd2da 100644 --- a/crates/oxc_minifier/tests/mod.rs +++ b/crates/oxc_minifier/tests/mod.rs @@ -6,7 +6,7 @@ mod oxc; mod tdewolff; mod terser; -use oxc_minifier::{CompressOptions, Minifier, MinifierOptions, PrinterOptions}; +use oxc_minifier::{CodegenOptions, CompressOptions, Minifier, MinifierOptions}; use oxc_span::SourceType; pub(crate) fn test(source_text: &str, expected: &str) { @@ -36,7 +36,7 @@ pub(crate) fn test_without_compress_booleans(source_text: &str, expected: &str) let source_type = SourceType::default(); let compress_options = CompressOptions { booleans: false, ..CompressOptions::default() }; let options = - MinifierOptions { mangle: false, compress: compress_options, print: PrinterOptions }; + MinifierOptions { mangle: false, compress: compress_options, codegen: CodegenOptions }; let minified = Minifier::new(source_text, source_type, options).build(); assert_eq!(expected, minified, "for source {source_text}"); } diff --git a/crates/oxc_minifier/tests/terser/mod.rs b/crates/oxc_minifier/tests/terser/mod.rs index 7da9de32a0e3e8..08f613b606f2ec 100644 --- a/crates/oxc_minifier/tests/terser/mod.rs +++ b/crates/oxc_minifier/tests/terser/mod.rs @@ -1,7 +1,7 @@ use oxc_allocator::Allocator; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; -use oxc_minifier::{CompressOptions, Minifier, MinifierOptions, PrinterOptions}; +use oxc_minifier::{CodegenOptions, CompressOptions, Minifier, MinifierOptions}; use oxc_parser::Parser; use oxc_span::{SourceType, Span}; use walkdir::WalkDir; @@ -68,7 +68,7 @@ impl TestCase { let options = MinifierOptions { mangle: false, compress: self.compress_options, - print: PrinterOptions, + codegen: CodegenOptions, }; let minified_source_text = Minifier::new(self.input.as_ref(), source_type, options).build(); assert_eq!(