Skip to content

Commit

Permalink
close #1338 where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiosantoscode committed Mar 21, 2023
1 parent ad25da4 commit df3cb5c
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 6 deletions.
83 changes: 83 additions & 0 deletions lib/compress/reduce-vars.js
Expand Up @@ -71,9 +71,11 @@ import {
AST_Number,
AST_ObjectKeyVal,
AST_PropAccess,
AST_Scope,
AST_Sequence,
AST_SimpleStatement,
AST_Symbol,
AST_SymbolBlockDeclaration,
AST_SymbolCatch,
AST_SymbolConst,
AST_SymbolDefun,
Expand All @@ -91,6 +93,7 @@ import {
AST_Yield,

walk,
walk_abort,
walk_body,

_INLINE,
Expand Down Expand Up @@ -482,9 +485,86 @@ function mark_lambda(tw, descend, compressor) {
descend();
pop(tw);

handle_defined_after_hoist(this);

return true;
}

/**
* It's possible for a hoisted function to use something that's not defined yet. Example:
*
* hoisted();
* var defined_after = true;
* function hoisted() {
* // use defined_after
* }
*
* This function is called on the parent to handle this issue.
*/
function handle_defined_after_hoist(parent) {
const defuns = [];
walk(parent, node => {
if (node === parent) return;
if (node instanceof AST_Defun) defuns.push(node);
if (
node instanceof AST_Scope
|| node instanceof AST_SimpleStatement
) return true;
});

for (const defun of defuns) {
const fname_def = defun.name.definition();
const found_self_ref_in_other_defuns = defuns.some(
d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
);

for (const def of defun.enclosed) {
if (
def.fixed === false
|| def === fname_def
|| def.scope.get_defun_scope() !== parent
) {
continue;
}

// defun is hoisted, so always safe
if (
def.assignments === 0
&& def.orig.length === 1
&& def.orig[0] instanceof AST_SymbolDefun
) {
continue;
}

if (found_self_ref_in_other_defuns) {
def.fixed = false;
continue;
}

// Detect `call_defun(); var used_in_defun = ...`
// Because `used_in_defun` can no longer be fixed
let found_defun = false;
let found_def_after_defun = false;
walk(parent, node => {
if (node === defun) return true;

if (node instanceof AST_Symbol) {
if (!found_defun && node.thedef === fname_def) {
found_defun = true;
} else if (found_defun && node.thedef === def) {
found_def_after_defun = true;
return walk_abort;
}
}
});

if (found_def_after_defun) {
def.fixed = false;
}
}
}
}

def_reduce_vars(AST_Lambda, mark_lambda);

def_reduce_vars(AST_Do, function(tw, descend, compressor) {
Expand Down Expand Up @@ -605,6 +685,9 @@ def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) {
reset_def(compressor, def);
});
reset_variables(tw, compressor, this);
descend();
handle_defined_after_hoist(this);
return true;
});

def_reduce_vars(AST_Try, function(tw, descend, compressor) {
Expand Down
101 changes: 95 additions & 6 deletions test/compress/reduce_vars.js
Expand Up @@ -1278,7 +1278,73 @@ defun_reference_1: {
}
}

defun_reference_2: {
defun_reference_indirection_1: {
options = {
toplevel: true,
reduce_vars: true,
unused: true,
evaluate: true
}
input: {
if (id(true)) {
var first = indirection();
var on = true;
function indirection() {
log_on()
}
function log_on() {
console.log(on)
}
}
}
expect: {
if (id(true)) {
(function () {
log_on();
})();
var on = true;
function log_on() {
console.log(on);
}
}
}
expect_stdout: "undefined"
}

defun_reference_indirection_2: {
options = {
toplevel: true,
reduce_vars: true,
unused: true,
evaluate: true
}
input: {
if (id(true)) {
var first = indirection_2();
var on = true;
function log_on() {
console.log(on)
}
function indirection_2() {
log_on()
}
}
}
expect: {
if (id(true)) {
(function () {
log_on();
})();
var on = true;
function log_on() {
console.log(on);
}
}
}
expect_stdout: "undefined"
}

defun_reference_used_before_def: {
options = {
toplevel: true,
reduce_vars: true,
Expand All @@ -1301,7 +1367,7 @@ defun_reference_2: {
expect_stdout: "undefined"
}

defun_reference_3: {
defun_reference_fixed: {
options = {
toplevel: true,
reduce_vars: true,
Expand All @@ -1310,8 +1376,8 @@ defun_reference_3: {
}
input: {
if (id(true)) {
var first = log_on();
var on = true;
var first = log_on();
function log_on() {
console.log(on)
}
Expand All @@ -1320,14 +1386,37 @@ defun_reference_3: {
expect: {
if (id(true)) {
(function () {
console.log(on)
console.log(true)
})();
var on = true;
}
}
expect_stdout: "undefined"
expect_stdout: "true"
}

defun_reference_fixed_let: {
options = {
toplevel: true,
reduce_vars: true,
unused: true,
evaluate: true,
passes: 3
}
input: {
let on = true;
function log_on() {
console.log(on)
}
var first = log_on();
}
expect: {
(function () {
console.log(true)
})();
}
expect_stdout: "true"
}


defun_inline_1: {
options = {
reduce_funcs: true,
Expand Down

0 comments on commit df3cb5c

Please sign in to comment.