+45
| // Copyright (C) 2014-2015 Free Software Foundation, Inc. | ||
| // This program is free software; you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 'use strict'; | ||
| var scopifier = require('./scopifier'); | ||
| // Read in source code from stdin, then write scope data back out. | ||
| function read() { | ||
| var whole = ''; | ||
| process.stdin.setEncoding('utf8'); | ||
| process.stdin.on('readable', function () { | ||
| var chunk = process.stdin.read(); | ||
| if (chunk !== null) { | ||
| whole += chunk; | ||
| } | ||
| }); | ||
| process.stdin.on('end', function () { | ||
| var json; | ||
| try { | ||
| json = JSON.stringify(scopifier(whole)); | ||
| } catch (error) { | ||
| // Gracefully handle parse errors by doing nothing. | ||
| process.exit(1); | ||
| } | ||
| console.log(json); | ||
| }); | ||
| } | ||
| module.exports = read; |
+4
-13
| { | ||
| "bitwise": true, | ||
| "camelcase": true, | ||
| "curly": true, | ||
| "devel": true, | ||
| "eqeqeq": true, | ||
| "forin": true, | ||
| "forin" : true, | ||
| "freeze": true, | ||
| "funcscope": true, | ||
| "immed": true, | ||
| "indent": 4, | ||
| "futurehostile": true, | ||
| "latedef": true, | ||
| "newcap": true, | ||
| "noarg": true, | ||
| "nocomma": true, | ||
| "node": true, | ||
| "noempty": true, | ||
| "nonbsp": true, | ||
| "nonew": true, | ||
| "plusplus": true, | ||
| "quotmark": "single", | ||
| "strict": true, | ||
| "undef": true, | ||
| "unused": "strict" | ||
| "unused": true | ||
| } |
+23
-23
@@ -20,27 +20,27 @@ #!/usr/bin/env node | ||
| var scopifier = require('./scopifier'), | ||
| whole; | ||
| var read = require('./read'), | ||
| server = require('./server'), | ||
| nopt = require('nopt'), | ||
| knownOptions = { | ||
| version: Boolean, | ||
| server: Boolean, | ||
| host: String, | ||
| port: Number | ||
| }, | ||
| parsed; | ||
| process.argv.slice(2).forEach(function (argument) { | ||
| switch (argument) { | ||
| case '--version': | ||
| console.log(require('./package.json').version); | ||
| process.exit(0); | ||
| break; | ||
| } | ||
| }); | ||
| parsed = nopt(knownOptions, {}, process.argv); | ||
| whole = ''; | ||
| if (parsed.version) { | ||
| console.log(require('./package.json').version); | ||
| process.exit(0); | ||
| } | ||
| process.stdin.setEncoding('utf8'); | ||
| process.stdin.on('readable', function () { | ||
| var chunk = process.stdin.read(); | ||
| if (chunk !== null) { | ||
| whole += chunk; | ||
| } | ||
| }); | ||
| process.stdin.on('end', function () { | ||
| console.log(JSON.stringify(scopifier(whole))); | ||
| }); | ||
| if (parsed.server) { | ||
| server({ | ||
| host: parsed.host, | ||
| port: parsed.port | ||
| }); | ||
| } else { | ||
| read(); | ||
| } |
+4
-3
| { | ||
| "name": "scopifier", | ||
| "version": "1.1.2", | ||
| "version": "1.2.0", | ||
| "description": "Scopifier CLI for Context Coloring", | ||
@@ -30,4 +30,5 @@ "main": "scopifier.js", | ||
| "dependencies": { | ||
| "escope": "^1.0.3", | ||
| "esprima": "^1.2.3" | ||
| "escope": "^3.1.0", | ||
| "esprima": "^2.2.0", | ||
| "nopt": "^3.0.2" | ||
| }, | ||
@@ -34,0 +35,0 @@ "devDependencies": { |
+55
-74
@@ -21,11 +21,2 @@ // Copyright (C) 2014-2015 Free Software Foundation, Inc. | ||
| // V8 hates try-catch statements and won't optimize a function that uses them. | ||
| function tryCatch(fn, failureHandler) { | ||
| try { | ||
| fn(); | ||
| } catch (error) { | ||
| failureHandler(error); | ||
| } | ||
| } | ||
| // Given code, returns an array of tokens for context-coloring. | ||
@@ -57,11 +48,6 @@ function scopifier(code) { | ||
| // Gracefully handle parse errors by doing nothing. | ||
| tryCatch(function () { | ||
| ast = esprima.parse(code, { | ||
| range: true | ||
| }); | ||
| analyzedScopes = escope.analyze(ast).scopes; | ||
| }, function () { | ||
| process.exit(1); | ||
| ast = esprima.parse(code, { | ||
| range: true | ||
| }); | ||
| analyzedScopes = escope.analyze(ast).scopes; | ||
@@ -72,64 +58,59 @@ scopes = []; | ||
| 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; | ||
| } | ||
| 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 { | ||
| // Base case. | ||
| scope.level = 0; | ||
| scope.level = scope.upper.level + 1; | ||
| } | ||
| // 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 | ||
| ); | ||
| 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 | ||
| ); | ||
| } | ||
| } else { | ||
| // Base case. | ||
| scope.level = 0; | ||
| } | ||
| if (!scope.functionExpressionScope) { | ||
| range = scope.block.range; | ||
| scopes.push( | ||
| range[0] + 1, | ||
| range[1] + 1, | ||
| scope.level | ||
| ); | ||
| 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 | ||
| ); | ||
| } | ||
| 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) { | ||
| pointer = definitionsIndex + (k * 3); | ||
| if (tokens[pointer] === range[0] + 1 && | ||
| tokens[pointer + 1] === range[1] + 1) { | ||
| isDefined = true; | ||
| break; | ||
| } | ||
| } | ||
| 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) { | ||
| pointer = definitionsIndex + (k * 3); | ||
| if (tokens[pointer] === range[0] + 1 && | ||
| tokens[pointer + 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 | ||
| ); | ||
| } | ||
| } | ||
| if (!isDefined) { | ||
| tokens.push( | ||
| // Handle global references too. | ||
| range[0] + 1, | ||
| range[1] + 1, | ||
| reference.resolved ? reference.resolved.scope.level : 0 | ||
| ); | ||
| } | ||
| } | ||
@@ -136,0 +117,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
-7
| bench: | ||
| node_modules/.bin/matcha benchmark/scenarios.js | ||
| v8: | ||
| node --allow-natives-syntax --trace-opt --trace-deopt benchmark/v8.js | ||
| .PHONY: bench v8 |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
178
11.95%8073
-28.03%3
50%7
-50%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
Updated
Updated