diff --git a/index.js b/index.js index af49ca8..9711418 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,9 @@ var lang = require('cssauron-glsl') , through = require('through') , shortest = require('shortest') +// recognize commutative + but not * as these are conditional +var commutative_operators = ['+', '&&', '||'] + function minifier(safe_words, mutate_storages) { safe_words = safe_words || ['main'] @@ -23,6 +26,18 @@ function minifier(safe_words, mutate_storages) { return through(mutate) function mutate(node) { + // remove unnecessary grouping operators + if(is_unnecessary_group(node)) return + + if(node.parent) { + for(var current = node.parent; current.parent; current = current.parent) { + if(is_unnecessary_group(current)) { + current.parent.children[current.parent.children.indexOf(current)] = current.children[0] + current.children[0].parent = current.parent + } + } + } + // vec2(1.0, 1.0) => vec2(1.0) if(node.parent && is_redundant_vector_literal(node.parent) && node.parent.children.indexOf(node) > 1) return if(is_redundant_vector_literal(node)) node.children = node.children.slice(0, 2) @@ -56,6 +71,17 @@ function minifier(safe_words, mutate_storages) { !safe_words.hasOwnProperty(node.token.data) } + function is_unnecessary_group(node) { + if(node.type !== 'group') return false + if(node.children[0].lbp > node.parent.lbp) return true + if(node.children[0].lbp === node.parent.lbp) { + for(var i = 0; i < commutative_operators.length; i++) { + if(node.parent.data === commutative_operators[i] && node.children[0].data === commutative_operators[i]) return true + } + } + return false + } + function is_redundant_vector_literal(node) { if(node.type === 'call' && /^[ib]?vec[234]$/.test(node.children[0].data) && (node.children[1].type === 'literal' || node.children[1].type === 'ident')) { diff --git a/tap-snapshots/test-basic.js-TAP.test.js b/tap-snapshots/test-basic.js-TAP.test.js index 709c5bc..3272e44 100644 --- a/tap-snapshots/test-basic.js-TAP.test.js +++ b/tap-snapshots/test-basic.js-TAP.test.js @@ -736,6 +736,14 @@ float f = .1; float g = .01; ` +exports[`test/basic.js TAP grouping removal test > output 1`] = ` + +float a = 2e10 + .2e2 + 1.e3 * (0xFaBc09 + 3); +float b = 2e10 + (.2e2 - 1.e3 / (0xFaBc09 + 3)); +bool c = 1. && true && true; +bool d = 0. || false || true; +` + exports[`test/basic.js TAP vec shorthand > output 1`] = ` vec2 vec2Long = vec2(.0, 1.); diff --git a/test/basic.js b/test/basic.js index 4888efc..63da188 100644 --- a/test/basic.js +++ b/test/basic.js @@ -9,6 +9,7 @@ const path = require("path"); const through = require("through"); const zeroGLSL = path.resolve(__dirname, "./zero-decimals.glsl"); +const commutativeGLSL = path.resolve(__dirname, "./commutative-operators.glsl"); const workingGLSL = path.resolve(__dirname, "./working.glsl"); const vecGLSL = path.resolve(__dirname, "./vec-shorthand.glsl"); @@ -85,7 +86,7 @@ tap.test("decimals starting or ending with 0", t => { fs.createReadStream(zeroGLSL) .pipe(tokenizer()) .pipe(parser()) - .pipe(minify(["main"], true)) + .pipe(minify()) .pipe(deparser()) .pipe(endStream); }); @@ -137,3 +138,22 @@ tap.test("vec shorthand", t => { .pipe(deparser()) .pipe(endStream); }); + +tap.test("grouping removal test", t => { + let output = ""; + + const endStream = through((data) => { + output += data; + }, () => { + t.matchSnapshot(output, "output"); + t.end(); + }); + + fs.createReadStream(commutativeGLSL) + .pipe(tokenizer()) + .pipe(parser()) + .pipe(minify()) + .pipe(deparser()) + .pipe(endStream); +}); + diff --git a/test/commutative-operators.glsl b/test/commutative-operators.glsl new file mode 100644 index 0000000..e48b55a --- /dev/null +++ b/test/commutative-operators.glsl @@ -0,0 +1,6 @@ +float x = 2e10 + (.2e2 + (1.e3 * (0xFaBc09 + 3))); +float y = 2e10 + (.2e2 - (1.e3 / (0xFaBc09 + 3))); + +bool a = 1. && (true && true); + +bool b = 0. || (false || true); diff --git a/test/test.glsl b/test/test.glsl index 0101edb..6a2f353 100644 --- a/test/test.glsl +++ b/test/test.glsl @@ -56,7 +56,7 @@ int first, second, third, fourth, fifth, sixth, seventh, eigth; vPosition = position; vec3 thing = vec2(1., 2.); int v_thing, garybusey; - thing.rgba = 2e10 + .2e2 + 1.e3 * 0xFaBc09 + (3 * v_thing); + thing.rgba = 2e10 + (.2e2 + (1.e3 * 0xFaBc09 + (3 * v_thing))); for(xxx i = 0; i < 10; ++i) { discard;