code to build JSON for tern code analysis

This commit is contained in:
Gordon Williams 2014-07-14 14:06:38 +01:00
parent 709d033451
commit f319ac498d
2 changed files with 171 additions and 0 deletions

View File

@ -0,0 +1,78 @@
#!/bin/node
// This build a JSON description file for Tern.js as
// specified here: http://ternjs.net/doc/manual.html#typedef
require("./common.js").readAllWrapperFiles(function(json) {
var tern = { "!name": "Espruino" };
// Handle classes/libraries first
json.forEach(function (j) {
try {
if (j.type=="class") {
var o = { "!type": "fn()" };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
tern[j.class] = o;
} else if (j.type=="object") {
var o = { "!type": ("instanceof" in j) ? ("+"+j.instanceof) : "?" };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
tern[j.name] = o;
} else if (j.type=="library") {
// TODO: bind this into 'require' somehow
var o = { "!type": "fn()" };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
tern[j.class] = o;
}
} catch (e) {
console.error("Exception "+e, j);
}
});
// Handle contents
json.forEach(function (j) {
try {
if (["include"].indexOf(j.type)>=0) {
// meh
} else if (["class","object","library"].indexOf(j.type)>=0) {
// aready handled above
} else if (["init","idle","kill"].indexOf(j.type)>=0) {
// internal
} else if (["event"].indexOf(j.type)>=0) {
// TODO: handle events
} else if (["constructor"].indexOf(j.type)>=0) {
var o = tern[j.class]; // overwrite existing class with constructor
o["!type"] = j.getTernType();
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
} else if (["staticproperty","staticmethod"].indexOf(j.type)>=0) {
var o = { "!type": j.getTernType() };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
tern[j.class][j.name] = o;
} else if (["property","method"].indexOf(j.type)>=0) {
var o = { "!type": j.getTernType() };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
if (!("prototype" in tern[j.class])) {
tern[j.class]["prototype"] = { };
if (["Object","Function","Array","String","Number","Boolean","RegExp"].indexOf(j.class)>=0)
tern[j.class]["prototype"]["!stdProto"] = j.class;
}
tern[j.class]["prototype"][j.name] = o;
} else if (["function","variable"].indexOf(j.type)>=0) {
var o = { "!type": j.getTernType() };
o["!doc"] = j.getDescription();
o["!url"] = j.getURL();
tern[j.name] = o;
} else
console.warn("Unknown type "+j.type+" for ",j);
} catch (e) {
console.error("Exception "+e, e.stack, j);
}
});
console.log(JSON.stringify(tern,null,4));
});

93
scripts/common.js Normal file
View File

@ -0,0 +1,93 @@
#!/bin/false
// common functions for parsing the JSON comments out of
// the C wrapper files (like common.py)
/// Object representing each builtin
function Builtin(j) {
// remove arrays of description - folw it down with newlines
if ("description" in j)
if (j.description instanceof Array)
j.description = j.description.join("\n\n");
for (var k in j)
this[k] = j[k];
}
Builtin.prototype.getDescription = function() {
var d = "";
if ("description" in this)
d = this.description;
if (d instanceof Array)
d = d.join("\n\n");
return d;
};
Builtin.prototype.getURL = function() {
if (this.type == "class")
anchor = this.class;
else if ("class" in this)
anchor = "l_"+this.class+"_"+this.name;
else
anchor = "l__global_"+this.name;
return "http://www.espruino.com/Reference#"+anchor;
};
/// Tern types - for tern.js json format
function getBasicTernType(t) {
if (["int","float","int32"].indexOf(t)>=0) return "number";
if (t=="pin") return "+Pin";
if (t=="bool") return "bool";
if (t=="JsVarArray") return "?"; // TODO: not right. Should be variable arg count
return "?";
}
/// Get full Tern type - for tern.js json format
Builtin.prototype.getTernType = function() {
if (["class","library"].indexOf(this.type)>=0) {
return "fn()";
} else if (["function","method","staticmethod","constructor"].indexOf(this.type)>=0) {
// it's a function
var args = [];
if ("params" in this)
args = this.params.map(function (p) {
return p[0]+": "+getBasicTernType(p[1]);
});
var ret = "";
if ("return" in this)
ret = " -> "+getBasicTernType(this.return[0]);
return "fn("+args.join("\, ")+")"+ret;
} else {
return getBasicTernType(this.return[0]);
}
};
/// Get any files that we think might contain 'JSON' tags
exports.getWrapperFiles = function (callback) {
require('child_process').exec("find .. -name jswrap*.c", function(error, stdout, stderr) {
callback(stdout.toString().trim().split("\n"));
});
}
/// Extract the /*JSON ... */ comments from a file and parse them
exports.readWrapperFile = function(filename) {
var contents = require("fs").readFileSync(filename).toString();
var builtins = [];
var comments = contents.match( /\/\*JSON(?:(?!\*\/).|[\n\r])*\*\//g );
if (comments) comments.forEach(function(comment) {
var j = new Builtin(JSON.parse(comment.slice(6,-2)));
j.implementation = filename;
builtins.push(j);
});
return builtins;
}
/// Extract all parsed /*JSON ... */ comments from all files
exports.readAllWrapperFiles = function(callback) {
exports.getWrapperFiles(function(files) {
var builtins = [];
files.forEach(function(filename) {
builtins = builtins.concat(exports.readWrapperFile(filename));
});
callback(builtins);
});
}