Bug 967813 - Change loader alias for acorn and add acorn/util/walk.js. r=fitzgen

This commit is contained in:
Brandon Benvie 2014-02-06 12:39:04 -08:00
parent d772e0f3c8
commit caae68189e
10 changed files with 333 additions and 12 deletions

View File

@ -68,8 +68,8 @@ BuiltinProvider.prototype = {
"devtools/client": "resource://gre/modules/devtools/client",
"devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js",
"acorn": "resource://gre/modules/devtools/acorn.js",
"acorn_loose": "resource://gre/modules/devtools/acorn_loose.js",
"acorn": "resource://gre/modules/devtools/acorn",
"acorn/util/walk": "resource://gre/modules/devtools/acorn/walk.js",
// Allow access to xpcshell test items from the loader.
"xpcshell-test": "resource://test"
@ -115,7 +115,7 @@ SrcdirProvider.prototype = {
let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client"));
let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js");
let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn"));
let acornLoosseURI = this.fileURI(OS.Path.join(toolkitDir, "acorn_loose.js"));
let acornWalkURI = OS.Path.join(acornURI, "walk.js");
this.loader = new loader.Loader({
modules: {
"toolkit/loader": loader,
@ -136,7 +136,7 @@ SrcdirProvider.prototype = {
"devtools/pretty-fast": prettyFastURI,
"acorn": acornURI,
"acorn_loose": acornLoosseURI
"acorn/util/walk": acornWalkURI
},
globals: loaderGlobals,
invisibleToDebugger: this.invisibleToDebugger

View File

@ -22,3 +22,7 @@ to:
4. Copy acorn_loose.js to our tree:
$ cp acorn_loose.js /path/to/mozilla-central/toolkit/devtools/acorn/acorn_loose.js
5. Copy util/walk.js to our tree:
$ cp util/walk.js /path/to/mozilla-central/toolkit/devtools/acorn/walk.js

View File

@ -6,9 +6,10 @@
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
JS_MODULES_PATH = 'modules/devtools'
JS_MODULES_PATH = 'modules/devtools/acorn'
EXTRA_JS_MODULES += [
'acorn.js',
'acorn_loose.js',
'walk.js',
]

View File

@ -6,10 +6,13 @@
*/
function run_test() {
const acorn = require("acorn");
const acorn_loose = require("acorn_loose");
const acorn = require("acorn/acorn");
const acorn_loose = require("acorn/acorn_loose");
const walk = require("acorn/util/walk");
do_check_true(isObject(acorn));
do_check_true(isObject(acorn_loose));
do_check_true(isObject(walk));
do_check_eq(typeof acorn.parse, "function");
do_check_eq(typeof acorn_loose.parse_dammit, "function");
do_check_eq(typeof walk.simple, "function");
}

View File

@ -5,7 +5,7 @@
* Test that acorn's lenient parser gives something usable.
*/
const acorn_loose = require("acorn_loose");
const acorn_loose = require("acorn/acorn_loose");
function run_test() {
let actualAST = acorn_loose.parse_dammit("let x = 10");

View File

@ -5,7 +5,7 @@
* Test that Reflect and acorn create the same AST for ES5.
*/
const acorn = require("acorn");
const acorn = require("acorn/acorn");
Cu.import("resource://gre/modules/reflect.jsm");
const testCode = "" + function main () {

View File

@ -0,0 +1,313 @@
// AST walker module for Mozilla Parser API compatible trees
(function(mod) {
if (typeof exports == "object" && typeof module == "object") return mod(exports); // CommonJS
if (typeof define == "function" && define.amd) return define(["exports"], mod); // AMD
mod((this.acorn || (this.acorn = {})).walk = {}); // Plain browser env
})(function(exports) {
"use strict";
// A simple walk is one where you simply specify callbacks to be
// called on specific nodes. The last two arguments are optional. A
// simple use would be
//
// walk.simple(myTree, {
// Expression: function(node) { ... }
// });
//
// to do something with all expressions. All Parser API node types
// can be used to identify node types, as well as Expression,
// Statement, and ScopeBody, which denote categories of nodes.
//
// The base argument can be used to pass a custom (recursive)
// walker, and state can be used to give this walked an initial
// state.
exports.simple = function(node, visitors, base, state) {
if (!base) base = exports.base;
function c(node, st, override) {
var type = override || node.type, found = visitors[type];
base[type](node, st, c);
if (found) found(node, st);
}
c(node, state);
};
// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
// their child nodes (by calling their third argument on these
// nodes).
exports.recursive = function(node, state, funcs, base) {
var visitor = funcs ? exports.make(funcs, base) : base;
function c(node, st, override) {
visitor[override || node.type](node, st, c);
}
c(node, state);
};
function makeTest(test) {
if (typeof test == "string")
return function(type) { return type == test; };
else if (!test)
return function() { return true; };
else
return test;
}
function Found(node, state) { this.node = node; this.state = state; }
// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
exports.findNodeAt = function(node, start, end, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
var type = override || node.type;
if ((start == null || node.start <= start) &&
(end == null || node.end >= end))
base[type](node, st, c);
if (test(type, node) &&
(start == null || node.start == start) &&
(end == null || node.end == end))
throw new Found(node, st);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};
// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
exports.findNodeAround = function(node, pos, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
var type = override || node.type;
if (node.start > pos || node.end < pos) return;
base[type](node, st, c);
if (test(type, node)) throw new Found(node, st);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};
// Find the outermost matching node after a given position.
exports.findNodeAfter = function(node, pos, test, base, state) {
test = makeTest(test);
try {
if (!base) base = exports.base;
var c = function(node, st, override) {
if (node.end < pos) return;
var type = override || node.type;
if (node.start >= pos && test(type, node)) throw new Found(node, st);
base[type](node, st, c);
};
c(node, state);
} catch (e) {
if (e instanceof Found) return e;
throw e;
}
};
// Find the outermost matching node before a given position.
exports.findNodeBefore = function(node, pos, test, base, state) {
test = makeTest(test);
if (!base) base = exports.base;
var max;
var c = function(node, st, override) {
if (node.start > pos) return;
var type = override || node.type;
if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
max = new Found(node, st);
base[type](node, st, c);
};
c(node, state);
return max;
};
// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
exports.make = function(funcs, base) {
if (!base) base = exports.base;
var visitor = {};
for (var type in base) visitor[type] = base[type];
for (var type in funcs) visitor[type] = funcs[type];
return visitor;
};
function skipThrough(node, st, c) { c(node, st); }
function ignore(_node, _st, _c) {}
// Node walkers.
var base = exports.base = {};
base.Program = base.BlockStatement = function(node, st, c) {
for (var i = 0; i < node.body.length; ++i)
c(node.body[i], st, "Statement");
};
base.Statement = skipThrough;
base.EmptyStatement = ignore;
base.ExpressionStatement = function(node, st, c) {
c(node.expression, st, "Expression");
};
base.IfStatement = function(node, st, c) {
c(node.test, st, "Expression");
c(node.consequent, st, "Statement");
if (node.alternate) c(node.alternate, st, "Statement");
};
base.LabeledStatement = function(node, st, c) {
c(node.body, st, "Statement");
};
base.BreakStatement = base.ContinueStatement = ignore;
base.WithStatement = function(node, st, c) {
c(node.object, st, "Expression");
c(node.body, st, "Statement");
};
base.SwitchStatement = function(node, st, c) {
c(node.discriminant, st, "Expression");
for (var i = 0; i < node.cases.length; ++i) {
var cs = node.cases[i];
if (cs.test) c(cs.test, st, "Expression");
for (var j = 0; j < cs.consequent.length; ++j)
c(cs.consequent[j], st, "Statement");
}
};
base.ReturnStatement = function(node, st, c) {
if (node.argument) c(node.argument, st, "Expression");
};
base.ThrowStatement = function(node, st, c) {
c(node.argument, st, "Expression");
};
base.TryStatement = function(node, st, c) {
c(node.block, st, "Statement");
if (node.handler) c(node.handler.body, st, "ScopeBody");
if (node.finalizer) c(node.finalizer, st, "Statement");
};
base.WhileStatement = function(node, st, c) {
c(node.test, st, "Expression");
c(node.body, st, "Statement");
};
base.DoWhileStatement = base.WhileStatement;
base.ForStatement = function(node, st, c) {
if (node.init) c(node.init, st, "ForInit");
if (node.test) c(node.test, st, "Expression");
if (node.update) c(node.update, st, "Expression");
c(node.body, st, "Statement");
};
base.ForInStatement = function(node, st, c) {
c(node.left, st, "ForInit");
c(node.right, st, "Expression");
c(node.body, st, "Statement");
};
base.ForInit = function(node, st, c) {
if (node.type == "VariableDeclaration") c(node, st);
else c(node, st, "Expression");
};
base.DebuggerStatement = ignore;
base.FunctionDeclaration = function(node, st, c) {
c(node, st, "Function");
};
base.VariableDeclaration = function(node, st, c) {
for (var i = 0; i < node.declarations.length; ++i) {
var decl = node.declarations[i];
if (decl.init) c(decl.init, st, "Expression");
}
};
base.Function = function(node, st, c) {
c(node.body, st, "ScopeBody");
};
base.ScopeBody = function(node, st, c) {
c(node, st, "Statement");
};
base.Expression = skipThrough;
base.ThisExpression = ignore;
base.ArrayExpression = function(node, st, c) {
for (var i = 0; i < node.elements.length; ++i) {
var elt = node.elements[i];
if (elt) c(elt, st, "Expression");
}
};
base.ObjectExpression = function(node, st, c) {
for (var i = 0; i < node.properties.length; ++i)
c(node.properties[i].value, st, "Expression");
};
base.FunctionExpression = base.FunctionDeclaration;
base.SequenceExpression = function(node, st, c) {
for (var i = 0; i < node.expressions.length; ++i)
c(node.expressions[i], st, "Expression");
};
base.UnaryExpression = base.UpdateExpression = function(node, st, c) {
c(node.argument, st, "Expression");
};
base.BinaryExpression = base.AssignmentExpression = base.LogicalExpression = function(node, st, c) {
c(node.left, st, "Expression");
c(node.right, st, "Expression");
};
base.ConditionalExpression = function(node, st, c) {
c(node.test, st, "Expression");
c(node.consequent, st, "Expression");
c(node.alternate, st, "Expression");
};
base.NewExpression = base.CallExpression = function(node, st, c) {
c(node.callee, st, "Expression");
if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
c(node.arguments[i], st, "Expression");
};
base.MemberExpression = function(node, st, c) {
c(node.object, st, "Expression");
if (node.computed) c(node.property, st, "Expression");
};
base.Identifier = base.Literal = ignore;
// A custom walker that keeps track of the scope chain and the
// variables defined in it.
function makeScope(prev, isCatch) {
return {vars: Object.create(null), prev: prev, isCatch: isCatch};
}
function normalScope(scope) {
while (scope.isCatch) scope = scope.prev;
return scope;
}
exports.scopeVisitor = exports.make({
Function: function(node, scope, c) {
var inner = makeScope(scope);
for (var i = 0; i < node.params.length; ++i)
inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]};
if (node.id) {
var decl = node.type == "FunctionDeclaration";
(decl ? normalScope(scope) : inner).vars[node.id.name] =
{type: decl ? "function" : "function name", node: node.id};
}
c(node.body, inner, "ScopeBody");
},
TryStatement: function(node, scope, c) {
c(node.block, scope, "Statement");
if (node.handler) {
var inner = makeScope(scope, true);
inner.vars[node.handler.param.name] = {type: "catch clause", node: node.handler.param};
c(node.handler.body, inner, "ScopeBody");
}
if (node.finalizer) c(node.finalizer, scope, "Statement");
},
VariableDeclaration: function(node, scope, c) {
var target = normalScope(scope);
for (var i = 0; i < node.declarations.length; ++i) {
var decl = node.declarations[i];
target.vars[decl.id.name] = {type: "var", node: decl.id};
if (decl.init) c(decl.init, scope, "Expression");
}
}
});
});

View File

@ -14,7 +14,7 @@
}(this, function () {
"use strict";
var acorn = this.acorn || require("acorn");
var acorn = this.acorn || require("acorn/acorn");
var sourceMap = this.sourceMap || require("source-map");
var SourceNode = sourceMap.SourceNode;

View File

@ -8,7 +8,7 @@ const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {})
const { require } = devtools;
this.sourceMap = require("source-map");
this.acorn = require("acorn");
this.acorn = require("acorn/acorn");
this.prettyFast = require("devtools/pretty-fast");
const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});

View File

@ -27,7 +27,7 @@
* { id, error }
*/
importScripts("resource://gre/modules/devtools/acorn.js");
importScripts("resource://gre/modules/devtools/acorn/acorn.js");
importScripts("resource://gre/modules/devtools/source-map.js");
importScripts("resource://gre/modules/devtools/pretty-fast.js");