Skip to content

Instantly share code, notes, and snippets.

@emilisto
Last active December 17, 2015 23:08
Show Gist options
  • Save emilisto/5686611 to your computer and use it in GitHub Desktop.
Save emilisto/5686611 to your computer and use it in GitHub Desktop.
var esprima = require('esprima')
, readit = require('readit')
, traverse = require('traverse')
, code = readit()
, prettyjson = require('prettyjson')
, _ = require('underscore')
, path = require('path')
, optimist = require('optimist')
;
// How I use it:
// for f in $(find node_modules -name "*.js" | head -n 40); do node tree-stats.js $f; done 2>/dev/null | grep 'nLeaves/' | awk '{print $2}'
var code = readit();
var ast = esprima.parse(code);
var data = {};
data['filename'] = path.basename(optimist.argv._[0]);
var leaves = traverse(ast).reduce(function (acc, x) {
if (this.isLeaf) acc.push(x);
return acc;
}, []);
data['nLeaves'] = leaves.length;
var nodes = traverse(ast).reduce(function (acc, x) {
acc.push(x);
return acc;
}, []);
data['nNodes'] = nodes.length;
data['nNodes/nLeaves'] = (nodes.length / leaves.length).toFixed(2);
console.log(data);

I'm looking into how the AST can be used to extract interesting stuff about Javascript, and discovered that the nodes to leaves ratio is on average 1.65 ± 0.05. This number, being so consistent (a standard deviation of 3%) over a lot of node.js code, makes me curious. The

% node tree-stats.js ~/dev/ast/others/esprima/esprima.js
         filename: /Users/emil/dev/ast/others/esprima/esprima.js
          nLeaves: 22590
           nNodes: 36260
   nNodes/nLeaves: 1.61
% node tree-stats.js simple-nested.js
          nLeaves: 67
           nNodes: 114
   nNodes/nLeaves: 1.70
# Hmm, suspicious?
% for f in $(find node_modules -name "*.js" | head -n 100); do node tree-stats.js $f; done 2>/dev/null | grep 'nLeaves/' | awk '{print $2}' | node statistics.js
   samples: 75
      mean: 1.65
     stdev: 0.05
var byline = require('byline');
var Stats = require('fast-stats').Stats;
var stream = byline(process.stdin);
var stats = new Stats();
stream.on('data', function(line) {
if(!line.match(/^[\d.]+/)) return;
var n = parseFloat(line);
stats.push(n);
});
stream.on('end', function() {
console.log({
'samples' : stats.length,
'mean' : stats.gmean().toFixed(2),
'stdev' : stats.σ().toFixed(2)
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment