Add a method of dumping the AST
This commit is contained in:
parent
8430123e9d
commit
51e944b7da
|
|
@ -76,6 +76,7 @@ You need to pass an argument to this option to specify the name that your module
|
||||||
.describe("name-cache", "File to hold mangled names mappings")
|
.describe("name-cache", "File to hold mangled names mappings")
|
||||||
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
|
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
|
||||||
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
|
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
|
||||||
|
.describe("dump-ast", "Dump the AST instead of generating output")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
|
|
@ -130,6 +131,7 @@ You need to pass an argument to this option to specify the name that your module
|
||||||
.boolean("bare-returns")
|
.boolean("bare-returns")
|
||||||
.boolean("keep-fnames")
|
.boolean("keep-fnames")
|
||||||
.boolean("reserve-domprops")
|
.boolean("reserve-domprops")
|
||||||
|
.boolean("dump-ast")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
|
|
@ -476,7 +478,8 @@ async.eachLimit(files, 1, function (file, cb) {
|
||||||
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2));
|
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2));
|
||||||
} else {
|
} else {
|
||||||
time_it("generate", function(){
|
time_it("generate", function(){
|
||||||
TOPLEVEL.print(output);
|
if (ARGS.dump_ast) output.print(TOPLEVEL.dump());
|
||||||
|
else TOPLEVEL.print(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
output = output.get();
|
output = output.get();
|
||||||
|
|
|
||||||
35
lib/ast.js
35
lib/ast.js
|
|
@ -47,11 +47,24 @@ function DEFNODE(type, props, methods, base) {
|
||||||
if (arguments.length < 4) base = AST_Node;
|
if (arguments.length < 4) base = AST_Node;
|
||||||
if (!props) props = [];
|
if (!props) props = [];
|
||||||
else props = props.split(/\s+/);
|
else props = props.split(/\s+/);
|
||||||
|
var dump_props = [];
|
||||||
|
props = props.map(function(prop){
|
||||||
|
if (/!$/.test(prop)) {
|
||||||
|
prop = prop.slice(0, -1);
|
||||||
|
} else {
|
||||||
|
dump_props.push(prop);
|
||||||
|
}
|
||||||
|
return prop;
|
||||||
|
});
|
||||||
var self_props = props;
|
var self_props = props;
|
||||||
if (base && base.PROPS)
|
if (base) {
|
||||||
props = props.concat(base.PROPS);
|
if (base.PROPS) props = props.concat(base.PROPS);
|
||||||
var code = "return function AST_" + type + "(props){ if (props) { ";
|
if (base.DUMP_PROPS) dump_props = dump_props.concat(base.DUMP_PROPS);
|
||||||
for (var i = props.length; --i >= 0;) {
|
}
|
||||||
|
var code = "return function AST_" + type + "(props){";
|
||||||
|
if (type) { code += "this._class = 'AST_" + type + "';"; }
|
||||||
|
code += " if (props) { ";
|
||||||
|
for (var i = 0; i < props.length; ++i) {
|
||||||
code += "this." + props[i] + " = props." + props[i] + ";";
|
code += "this." + props[i] + " = props." + props[i] + ";";
|
||||||
}
|
}
|
||||||
var proto = base && new base;
|
var proto = base && new base;
|
||||||
|
|
@ -66,6 +79,7 @@ function DEFNODE(type, props, methods, base) {
|
||||||
if (base) base.SUBCLASSES.push(ctor);
|
if (base) base.SUBCLASSES.push(ctor);
|
||||||
ctor.prototype.CTOR = ctor;
|
ctor.prototype.CTOR = ctor;
|
||||||
ctor.PROPS = props || null;
|
ctor.PROPS = props || null;
|
||||||
|
ctor.DUMP_PROPS = dump_props.sort();
|
||||||
ctor.SELF_PROPS = self_props;
|
ctor.SELF_PROPS = self_props;
|
||||||
ctor.SUBCLASSES = [];
|
ctor.SUBCLASSES = [];
|
||||||
if (type) {
|
if (type) {
|
||||||
|
|
@ -88,7 +102,7 @@ function DEFNODE(type, props, methods, base) {
|
||||||
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
|
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
var AST_Node = DEFNODE("Node", "start end", {
|
var AST_Node = DEFNODE("Node", "start! end!", {
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new this.CTOR(this);
|
return new this.CTOR(this);
|
||||||
},
|
},
|
||||||
|
|
@ -102,6 +116,9 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
return this._walk(visitor); // not sure the indirection will be any help
|
return this._walk(visitor); // not sure the indirection will be any help
|
||||||
|
},
|
||||||
|
dump: function () {
|
||||||
|
return JSON.stringify(dump_internal(this), null, 2);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
|
|
@ -121,7 +138,7 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
||||||
$documentation: "Represents a debugger statement",
|
$documentation: "Represents a debugger statement",
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
var AST_Directive = DEFNODE("Directive", "value scope! quote", {
|
||||||
$documentation: "Represents a directive, like \"use strict\";",
|
$documentation: "Represents a directive, like \"use strict\";",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||||
|
|
@ -278,7 +295,7 @@ var AST_With = DEFNODE("With", "expression", {
|
||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
var AST_Scope = DEFNODE("Scope", "directives variables! functions! uses_with! uses_eval! parent_scope! enclosed! cname!", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
directives: "[string*/S] an array of directives declared in this scope",
|
directives: "[string*/S] an array of directives declared in this scope",
|
||||||
|
|
@ -292,7 +309,7 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
|
||||||
},
|
},
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals!", {
|
||||||
$documentation: "The toplevel scope",
|
$documentation: "The toplevel scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
|
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
|
||||||
|
|
@ -789,7 +806,7 @@ var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||||
$documentation: "An object getter property",
|
$documentation: "An object getter property",
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
var AST_Symbol = DEFNODE("Symbol", "scope! name thedef!", {
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[string] name of this symbol",
|
name: "[string] name of this symbol",
|
||||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||||
|
|
|
||||||
21
lib/utils.js
21
lib/utils.js
|
|
@ -214,6 +214,27 @@ function set_intersection(a, b) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function dump_internal(val) {
|
||||||
|
if (val) {
|
||||||
|
if (typeof val.map == 'function') {
|
||||||
|
return val.filter(function (x) {
|
||||||
|
return x != null;
|
||||||
|
}).map(dump_internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val.CTOR) {
|
||||||
|
var out = {_class: val._class};
|
||||||
|
val.CTOR.DUMP_PROPS.forEach(function(prop){
|
||||||
|
if (val[prop] != null) {
|
||||||
|
out[prop] = dump_internal(val[prop]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
// this function is taken from Acorn [1], written by Marijn Haverbeke
|
// this function is taken from Acorn [1], written by Marijn Haverbeke
|
||||||
// [1] https://github.com/marijnh/acorn
|
// [1] https://github.com/marijnh/acorn
|
||||||
function makePredicate(words) {
|
function makePredicate(words) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user