branch: master commit 28667b864aa79308922e90de856495378b085a4d Author: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com> Commit: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com>
Move microoptimized scopifier into the limelight. --- benchmark/scenarios.js | 32 +++----- bin/cli.js | 2 +- scopifier-microoptimized.js | 125 ----------------------------- scopifier.js | 187 ++++++++++++++++++++++--------------------- test/specs.js | 14 +--- 5 files changed, 109 insertions(+), 251 deletions(-) diff --git a/benchmark/scenarios.js b/benchmark/scenarios.js index 9af75da..29e55c3 100644 --- a/benchmark/scenarios.js +++ b/benchmark/scenarios.js @@ -3,7 +3,6 @@ var fs = require('fs'), path = require('path'), scopifier = require('../scopifier'), - scopifierMicrooptimized = require('../scopifier-microoptimized'), jqueryPath = path.join(__dirname, 'fixtures', 'jquery-2.1.1.js'), lodashPath = path.join(__dirname, 'fixtures', 'lodash-2.4.1.js'), @@ -39,26 +38,17 @@ suite('scopifier', function () { }); }); - [scopifier, scopifierMicrooptimized].forEach(function (scopifier, index) { - var message = ''; - if (!scopifier) { - return; - } - if (index === 1) { - message = ' (microoptimized)'; - } - bench('jquery' + message, function () { - scopifier(jquery); - }); - bench('lodash' + message, function () { - scopifier(lodash); - }); - bench('async' + message, function () { - scopifier(async); - }); - bench('mkdirp' + message, function () { - scopifier(mkdirp); - }); + bench('jquery', function () { + scopifier(jquery); + }); + bench('lodash', function () { + scopifier(lodash); + }); + bench('async', function () { + scopifier(async); + }); + bench('mkdirp', function () { + scopifier(mkdirp); }); }); diff --git a/bin/cli.js b/bin/cli.js index 3adfe82..3453b33 100644 --- a/bin/cli.js +++ b/bin/cli.js @@ -4,7 +4,7 @@ 'use strict'; -var scopifier = require('../scopifier-microoptimized'), +var scopifier = require('../scopifier'), whole = ''; process.stdin.setEncoding('utf8'); diff --git a/scopifier-microoptimized.js b/scopifier-microoptimized.js deleted file mode 100644 index 0cc4f77..0000000 --- a/scopifier-microoptimized.js +++ /dev/null @@ -1,125 +0,0 @@ -'use strict'; - -var escope = require('escope'), - esprima = require('esprima'), - - normal = 0, - bold = 1, - italic = 2; - -// Given code, returns an array of `[start, end, level, style]' tokens for -// context-coloring. -module.exports = function (code) { - var analyzedScopes, - ast, - comment, - definition, - definitionsCount, - definitionsIndex, - i, - isDefined, - j, - k, - range, - reference, - scope, - scopes = [], - tokens = [], - variable; - - // Gracefully handle parse errors by doing nothing. - try { - ast = esprima.parse(code, { - comment: true, - range: true - }); - analyzedScopes = escope.analyze(ast).scopes; - } catch (error) { - process.exit(1); - } - - for (i = 0; i < analyzedScopes.length; i += 1) { - scope = analyzedScopes[i]; - // Having its level set implies it was already annotated. - if (scope.level === undefined) { - if (scope.upper) { - if (scope.upper.functionExpressionScope) { - // Pretend function expression scope doesn't exist. - scope.level = scope.upper.level; - scope.variables = scope.upper.variables.concat(scope.variables); - } else { - scope.level = scope.upper.level + 1; - } - } else { - // Base case. - scope.level = 0; - } - // We've only given the scope a level for posterity's sake. We're - // done now. - if (!scope.functionExpressionScope) { - range = scope.block.range; - scopes.push([ - range[0] + 1, - range[1] + 1, - scope.level, - normal - ]); - definitionsIndex = tokens.length; - definitionsCount = 0; - for (j = 0; j < scope.variables.length; j += 1) { - variable = scope.variables[j]; - definitionsCount += variable.defs.length; - for (k = 0; k < variable.defs.length; k += 1) { - definition = variable.defs[k]; - range = definition.name.range; - tokens.push([ - range[0] + 1, - range[1] + 1, - scope.level, - bold - ]); - } - } - for (j = 0; j < scope.references.length; j += 1) { - reference = scope.references[j]; - range = reference.identifier.range; - isDefined = false; - // Determine if a definition already exists for the - // range. (escope detects variables twice if they are - // declared and initialized simultaneously; this filters - // them.) - for (k = 0; k < definitionsCount; k += 1) { - definition = tokens[definitionsIndex + k]; - if (definition[0] === range[0] + 1 && - definition[1] === range[1] + 1) { - isDefined = true; - break; - } - } - if (!isDefined) { - tokens.push([ - // Handle global references too. - range[0] + 1, - range[1] + 1, - reference.resolved ? reference.resolved.scope.level : 0, - reference.__maybeImplicitGlobal ? bold : normal - ]); - } - } - } - } - } - - for (i = 0; i < ast.comments.length; i += 1) { - comment = ast.comments[i]; - range = comment.range; - tokens.push([ - range[0] + 1, - range[1] + 1, - -1, - italic - ]); - } - - return scopes.concat(tokens); -}; diff --git a/scopifier.js b/scopifier.js index 377870e..4b54091 100644 --- a/scopifier.js +++ b/scopifier.js @@ -3,17 +3,6 @@ var escope = require('escope'), esprima = require('esprima'), - // Given an array of definitions, determines if a definition already exists - // for a given range. (escope detects variables twice if they are declared - // and initialized simultaneously; this filters them.) - isDefined = function (definitions, range) { - return definitions.some(function (definition) { - // Check for identical definitions. - return definition[0] === range[0] && - definition[1] === range[1]; - }); - }, - normal = 0, bold = 1, italic = 2; @@ -21,12 +10,22 @@ var escope = require('escope'), // Given code, returns an array of `[start, end, level, style]' tokens for // context-coloring. module.exports = function (code) { - var ast, - analyzedScopes, - scopes = [], - symbols = [], - comments, - emacsified; + var analyzedScopes, + ast, + comment, + definition, + definitionsCount, + definitionsIndex, + i, + isDefined, + j, + k, + range, + reference, + scope, + scopes, + tokens, + variable; // Gracefully handle parse errors by doing nothing. try { @@ -39,87 +38,91 @@ module.exports = function (code) { process.exit(1); } - analyzedScopes.forEach(function (scope) { - var definitions, - references; - if (scope.level !== undefined) { - // Having its level set implies it was already annotated. - return; - } - if (scope.upper) { - if (scope.upper.functionExpressionScope) { - // Pretend function expression scope doesn't exist. - scope.level = scope.upper.level; - scope.variables = scope.upper.variables.concat(scope.variables); + scopes = []; + tokens = []; + + for (i = 0; i < analyzedScopes.length; i += 1) { + scope = analyzedScopes[i]; + // Having its level set implies it was already annotated. + if (scope.level === undefined) { + if (scope.upper) { + if (scope.upper.functionExpressionScope) { + // Pretend function expression scope doesn't exist. + scope.level = scope.upper.level; + scope.variables = scope.upper.variables.concat(scope.variables); + } else { + scope.level = scope.upper.level + 1; + } } else { - scope.level = scope.upper.level + 1; + // Base case. + scope.level = 0; } - } else { - // Base case. - scope.level = 0; - } - if (scope.functionExpressionScope) { // We've only given the scope a level for posterity's sake. We're // done now. - return; - } - scopes = scopes.concat([[ - scope.block.range[0], - scope.block.range[1], - scope.level, - normal - ]]); - definitions = scope.variables.reduce(function (definitions, variable) { - var mappedDefinitions = variable.defs.map(function (definition) { - var range = definition.name.range; - return [ - range[0], - range[1], + if (!scope.functionExpressionScope) { + range = scope.block.range; + scopes.push([ + range[0] + 1, + range[1] + 1, scope.level, - bold - ]; - }); - return definitions.concat(mappedDefinitions); - }, []); - references = scope.references.reduce(function (references, reference) { - var range = reference.identifier.range; - if (isDefined(definitions, range)) { - return references; + normal + ]); + definitionsIndex = tokens.length; + definitionsCount = 0; + for (j = 0; j < scope.variables.length; j += 1) { + variable = scope.variables[j]; + definitionsCount += variable.defs.length; + for (k = 0; k < variable.defs.length; k += 1) { + definition = variable.defs[k]; + range = definition.name.range; + tokens.push([ + range[0] + 1, + range[1] + 1, + scope.level, + bold + ]); + } + } + for (j = 0; j < scope.references.length; j += 1) { + reference = scope.references[j]; + range = reference.identifier.range; + isDefined = false; + // Determine if a definition already exists for the + // range. (escope detects variables twice if they are + // declared and initialized simultaneously; this filters + // them.) + for (k = 0; k < definitionsCount; k += 1) { + definition = tokens[definitionsIndex + k]; + if (definition[0] === range[0] + 1 && + definition[1] === range[1] + 1) { + isDefined = true; + break; + } + } + if (!isDefined) { + tokens.push([ + // Handle global references too. + range[0] + 1, + range[1] + 1, + reference.resolved ? reference.resolved.scope.level : 0, + reference.__maybeImplicitGlobal ? bold : normal + ]); + } + } } - return references.concat([[ - // Handle global references too. - range[0], - range[1], - reference.resolved ? reference.resolved.scope.level : 0, - reference.__maybeImplicitGlobal ? bold : normal - ]]); - }, []); - symbols = symbols.concat(definitions).concat(references); - }); - - comments = ast.comments - .map(function (comment) { - var range = comment.range; - return [ - range[0], - range[1], - -1, - italic - ]; - }); + } + } - emacsified = scopes - .concat(symbols) - .concat(comments) - .map(function (token) { - // Emacs starts counting from 1. - return [ - token[0] + 1, - token[1] + 1, - token[2], - token[3] - ]; - }); + for (i = 0; i < ast.comments.length; i += 1) { + comment = ast.comments[i]; + range = comment.range; + tokens.push([ + range[0] + 1, + range[1] + 1, + -1, + italic + ]); + } - return emacsified; + return scopes.concat(tokens); }; diff --git a/test/specs.js b/test/specs.js index 7634fc0..d59bc59 100644 --- a/test/specs.js +++ b/test/specs.js @@ -5,7 +5,6 @@ var assert = require('assert'), path = require('path'), scopifier = require('../scopifier'), - scopifierMicrooptimized = require('../scopifier-microoptimized'), inputPath = path.join(__dirname, 'fixtures', 'vow.js'), outputPath = path.join(__dirname, 'fixtures', 'vow.json'); @@ -40,17 +39,8 @@ describe('scopifier', function () { }); }); - [scopifier, scopifierMicrooptimized].forEach(function (scopifier, index) { - var message = ''; - if (!scopifier) { - return; - } - if (index === 1) { - message = ' (microoptimized)'; - } - it('should work' + message, function () { - assert.deepEqual(scopifier(input), output); - }); + it('should work', function () { + assert.deepEqual(scopifier(input), output); }); });