annotate-esprima/scripts/lib/esprima-master/assets/orion/contentassist/esprimaVisitor.js
2014-04-15 11:04:48 +02:00

119 lines
4 KiB
JavaScript
Executable file

/*******************************************************************************
* @license
* Copyright (c) 2012 VMware, Inc. All Rights Reserved.
* THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
* ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
* CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
* You can obtain a current copy of the Eclipse Public License from
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* Contributors:
* Andrew Eisenberg (VMware) - initial API and implementation
******************************************************************************/
/*global define esprima */
define("plugins/esprima/esprimaVisitor", function(scriptedLogger) {
return {
/**
* parses the contents with options that are appropriate for inferencing
*/
parse : function(contents, extraOptions) {
if (!extraOptions) {
extraOptions = {};
}
if (!extraOptions.range) {
extraOptions.range = true;
}
if (!extraOptions.tolerant) {
extraOptions.tolerant = true;
}
if (!extraOptions.comment) {
extraOptions.comment = true;
}
try {
var parsedProgram = esprima.parse(contents, extraOptions);
return parsedProgram;
} catch (e) {
if (typeof scriptedLogger !== "undefined") {
scriptedLogger.warn("Problem parsing file", "CONTENT_ASSIST");
scriptedLogger.warn(e.message, "CONTENT_ASSIST");
scriptedLogger.warn(e.stack, "CONTENT_ASSIST");
}
return null;
}
},
/**
* Generic AST visitor. Visits all children in source order, if they have a range property.
*
* @param node The AST node to visit
* @param {rhsVisit:Boolean,...} context any extra data required to pass between operations. Set rhsVisit to true if the rhs of
* assignments and variable declarators should be visited before the lhs
* @param operation function(node, context, [isInitialOp]) an operation on the AST node and the data. Return falsy if
* the visit should no longer continue. Return truthy to continue.
* @param [postoperation] (optional) function(node, context, [isInitialOp]) an operation that is exectuted after visiting the current node's children.
* will only be invoked if operation returns true for the current node
*/
visit: function(node, context, operation, postoperation) {
var i, key, child, children;
if (operation(node, context, true)) {
// gather children to visit
children = [];
for (key in node) {
if (key !== "range" && key !== "errors" && key !== "target" && key !== "extras" && key !== "comments") {
child = node[key];
if (child instanceof Array) {
for (i = 0; i < child.length; i++) {
if (child[i] && child[i].hasOwnProperty("type")) {
children.push(child[i]);
} else if (key === "properties") {
// might be key-value pair of an object expression
// in old versions of the parser, the 'properties' property did not have a 'type' or a 'range'
// so we must explicitly visit the children here.
// in new versions of the parser, this is fixed, and this branch will never be taken.
if (child[i].hasOwnProperty("key") && child[i].hasOwnProperty("value")) {
children.push(child[i].key);
children.push(child[i].value);
}
}
}
} else {
if (child && child.hasOwnProperty("type")) {
children.push(child);
}
}
}
}
if (children.length > 0) {
// sort children by source location
// children with no source location are visited first
children.sort(function(left, right) {
if (left.range && right.range) {
return left.range[0] - right.range[0];
} else if (left.range) {
return 1;
} else if (right.range) {
return -1;
} else {
return 0;
}
});
// visit children in order
for (i = 0; i < children.length; i++) {
this.visit(children[i], context, operation, postoperation);
}
}
if (postoperation) {
postoperation(node, context, false);
}
}
}
};
});