Bug 1568823 - Simplify parser.js and rename to parser-helper r=nchevobbe

Depends on D39335
Looking in details at get(), the implementation can also be simplified

Differential Revision: https://phabricator.services.mozilla.com/D39338

--HG--
rename : devtools/shared/webconsole/parser.js => devtools/shared/webconsole/parser-helper.js
extra : moz-landing-system : lando
This commit is contained in:
Julian Descottes 2019-07-25 13:21:03 +00:00
Родитель 5689ca6238
Коммит 0ab30c1e08
4 изменённых файлов: 76 добавлений и 162 удалений

Просмотреть файл

@ -11,8 +11,8 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
if (!isWorker) {
loader.lazyRequireGetter(
this,
"Parser",
"devtools/shared/webconsole/parser",
"getSyntaxTrees",
"devtools/shared/webconsole/parser-helper",
true
);
}
@ -399,13 +399,10 @@ function JSPropertyProvider({
// Don't run this is a worker, migrating to acorn should allow this
// to run in a worker - Bug 1217198.
if (!isWorker && lastCompletionCharIndex > 0) {
const parser = new Parser();
parser.logExceptions = false;
const parsedExpression = completionPart.slice(0, lastCompletionCharIndex);
const syntaxTree = parser.get(parsedExpression);
const lastTree = syntaxTree.getLastSyntaxTree();
const lastBody =
lastTree && lastTree.AST.body[lastTree.AST.body.length - 1];
const syntaxTrees = getSyntaxTrees(parsedExpression);
const lastTree = syntaxTrees[syntaxTrees.length - 1];
const lastBody = lastTree && lastTree.body[lastTree.body.length - 1];
// Finding the last expression since we've sliced up until the dot.
// If there were parse errors this won't exist.

Просмотреть файл

@ -27,6 +27,6 @@ ReservedWordsGenerated.inputs = ['/js/src/frontend/ReservedWords.h']
DevToolsModules(
'js-property-provider.js',
'network-helper.js',
'parser.js',
'parser-helper.js',
'throttle.js',
)

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
loader.lazyRequireGetter(
this,
"Reflect",
"resource://gre/modules/reflect.jsm",
true
);
/**
* Gets a collection of parser methods for a specified source.
*
* @param string source
* The source text content.
* @param boolean logExceptions
*/
function getSyntaxTrees(source, logExceptions) {
// The source may not necessarily be JS, in which case we need to extract
// all the scripts. Fastest/easiest way is with a regular expression.
// Don't worry, the rules of using a <script> tag are really strict,
// this will work.
const regexp = /<script[^>]*?(?:>([^]*?)<\/script\s*>|\/>)/gim;
const syntaxTrees = [];
const scriptMatches = [];
let scriptMatch;
if (source.match(/^\s*</)) {
// First non whitespace character is &lt, so most definitely HTML.
while ((scriptMatch = regexp.exec(source))) {
// Contents are captured at index 1 or nothing: Self-closing scripts
// won't capture code content
scriptMatches.push(scriptMatch[1] || "");
}
}
// If there are no script matches, send the whole source directly to the
// reflection API to generate the AST nodes.
if (!scriptMatches.length) {
// Reflect.parse throws when encounters a syntax error.
try {
syntaxTrees.push(Reflect.parse(source));
} catch (e) {
if (logExceptions) {
DevToolsUtils.reportException("Parser:get", e);
}
}
} else {
// Generate the AST nodes for each script.
for (const script of scriptMatches) {
// Reflect.parse throws when encounters a syntax error.
try {
syntaxTrees.push(Reflect.parse(script));
} catch (e) {
if (logExceptions) {
DevToolsUtils.reportException("Parser:get", e);
}
}
}
}
return syntaxTrees;
}
exports.getSyntaxTrees = getSyntaxTrees;

Просмотреть файл

@ -1,153 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
loader.lazyRequireGetter(
this,
"Reflect",
"resource://gre/modules/reflect.jsm",
true
);
/**
* A JS parser using the reflection API.
*/
const Parser = function Parser() {
this._cache = new Map();
this.errors = [];
this.logExceptions = true;
};
Parser.prototype = {
/**
* Gets a collection of parser methods for a specified source.
*
* @param string source
* The source text content.
* @param string url [optional]
* The source url. The AST nodes will be cached, so you can use this
* identifier to avoid parsing the whole source again.
*/
get(source, url = "") {
// Try to use the cached AST nodes, to avoid useless parsing operations.
if (this._cache.has(url)) {
return this._cache.get(url);
}
// The source may not necessarily be JS, in which case we need to extract
// all the scripts. Fastest/easiest way is with a regular expression.
// Don't worry, the rules of using a <script> tag are really strict,
// this will work.
const regexp = /<script[^>]*?(?:>([^]*?)<\/script\s*>|\/>)/gim;
const syntaxTrees = [];
const scriptMatches = [];
let scriptMatch;
if (source.match(/^\s*</)) {
// First non whitespace character is &lt, so most definitely HTML.
while ((scriptMatch = regexp.exec(source))) {
// Contents are captured at index 1 or nothing: Self-closing scripts
// won't capture code content
scriptMatches.push(scriptMatch[1] || "");
}
}
// If there are no script matches, send the whole source directly to the
// reflection API to generate the AST nodes.
if (!scriptMatches.length) {
// Reflect.parse throws when encounters a syntax error.
try {
const nodes = Reflect.parse(source);
const length = source.length;
syntaxTrees.push(new SyntaxTree(nodes, url, length));
} catch (e) {
this.errors.push(e);
if (this.logExceptions) {
DevToolsUtils.reportException(url, e);
}
}
} else {
// Generate the AST nodes for each script.
for (const script of scriptMatches) {
// Reflect.parse throws when encounters a syntax error.
try {
const nodes = Reflect.parse(script);
const offset = source.indexOf(script);
const length = script.length;
syntaxTrees.push(new SyntaxTree(nodes, url, length, offset));
} catch (e) {
this.errors.push(e);
if (this.logExceptions) {
DevToolsUtils.reportException(url, e);
}
}
}
}
const pool = new SyntaxTreesPool(syntaxTrees, url);
// Cache the syntax trees pool by the specified url. This is entirely
// optional, but it's strongly encouraged to cache ASTs because
// generating them can be costly with big/complex sources.
if (url) {
this._cache.set(url, pool);
}
return pool;
},
_cache: null,
errors: null,
};
exports.Parser = Parser;
/**
* A pool handling a collection of AST nodes generated by the reflection API.
*
* @param object syntaxTrees
* A collection of AST nodes generated for a source.
* @param string url [optional]
* The source url.
*/
function SyntaxTreesPool(syntaxTrees, url = "<unknown>") {
this._trees = syntaxTrees;
this._url = url;
this._cache = new Map();
}
SyntaxTreesPool.prototype = {
/**
* @return SyntaxTree
* The last tree in this._trees
*/
getLastSyntaxTree() {
return this._trees[this._trees.length - 1];
},
_trees: null,
_cache: null,
};
/**
* A collection of AST nodes generated by the reflection API.
*
* @param object nodes
* The AST nodes.
* @param string url
* The source url.
* @param number length
* The total number of chars of the parsed script in the parent source.
* @param number offset [optional]
* The char offset of the parsed script in the parent source.
*/
function SyntaxTree(nodes, url, length, offset = 0) {
this.AST = nodes;
this.url = url;
this.length = length;
this.offset = offset;
}