UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

115 lines 5.28 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TreeSitterExecutor = exports.DEFAULT_TREE_SITTER_WASM_PATH = exports.DEFAULT_TREE_SITTER_R_WASM_PATH = void 0; const web_tree_sitter_1 = __importDefault(require("web-tree-sitter")); const log_1 = require("../../../util/log"); const fs_1 = __importDefault(require("fs")); const incremental_parse_1 = require("../../../project/incremental/incremental-parse/incremental-parse"); exports.DEFAULT_TREE_SITTER_R_WASM_PATH = './node_modules/@davisvaughan/tree-sitter-r/tree-sitter-r.wasm'; exports.DEFAULT_TREE_SITTER_WASM_PATH = './node_modules/web-tree-sitter/tree-sitter.wasm'; const wasmLog = log_1.log.getSubLogger({ name: 'tree-sitter-wasm' }); /** * Synchronous and (way) faster alternative to the {@link RShell} using tree-sitter. */ class TreeSitterExecutor { name = 'tree-sitter'; parser; incremental = true; static language; /** * Initializes the underlying tree-sitter parser. This only needs to be called once globally. * @param config - The configuration for the tree-sitter engine, which can include paths to the wasm files. * @param overrideWasmPath - The path to the tree-sitter-r wasm file, which takes precedence over the config and default paths if set. * @param overrideTreeSitterWasmPath - The path to the tree-sitter wasm file, which takes precedence over the config and default paths if set. */ static async initTreeSitter(config, overrideWasmPath, overrideTreeSitterWasmPath) { const treeSitterWasmPath = overrideTreeSitterWasmPath ?? config?.treeSitterWasmPath ?? exports.DEFAULT_TREE_SITTER_WASM_PATH; // noinspection JSUnusedGlobalSymbols - this is used by emscripten, see https://emscripten.org/docs/api_reference/module.html await web_tree_sitter_1.default.init({ locateFile: treeSitterWasmPath ? (path, prefix) => { // allow setting a custom path for the tree sitter wasm file if (path.endsWith('tree-sitter.wasm')) { return treeSitterWasmPath; } return prefix + path; } : undefined, onAbort: (s) => wasmLog.error(`Tree-sitter wasm aborted: ${s}`), print: (s) => wasmLog.debug(s), printErr: (s) => wasmLog.error(s) }); const wasmPath = overrideWasmPath ?? config?.wasmPath ?? exports.DEFAULT_TREE_SITTER_R_WASM_PATH; TreeSitterExecutor.language = await web_tree_sitter_1.default.Language.load(wasmPath); } constructor() { this.parser = new web_tree_sitter_1.default(); this.parser.setLanguage(TreeSitterExecutor.language); } rVersion() { return Promise.resolve('none'); } information(analyzer) { return { name: 'tree-sitter', grammarVersion: this.treeSitterVersion(), treeSitterQuery: async (source, force) => { return this.query(source, ...(await analyzer.parse(force)).files.map(p => p.parsed)); } }; } treeSitterVersion() { return this.parser.getLanguage().version; } parse(request, ctx) { let sourceCode; if (request.request === 'file') { sourceCode = fs_1.default.readFileSync(request.content, 'utf8'); } else { sourceCode = request.content; } if (request.filePath === undefined || !ctx.inc.handleShouldReparse(request.filePath, ctx)) { return this.parser.parse(sourceCode); } const reparseInfo = (0, incremental_parse_1.computeReparseInfo)(ctx, request.filePath); // `computeReparseInfo` needs the stored old content to compute the edit against the // previous tree. Once that snapshot has been consumed, drop it so a later invalidation // can record a fresh old-content baseline for the next stored tree. ctx.inc.deleteOldContentOf(request.filePath); if (!reparseInfo) { // incremental parsing not possible return this.parser.parse(sourceCode); } if (!reparseInfo.editRegion) { return reparseInfo.previousTree; } const previousTree = reparseInfo.previousTree; previousTree.edit(reparseInfo.editRegion); return this.parser.parse(sourceCode, previousTree); } createQuery(source) { return this.parser.getLanguage().query(source); } query(source, ...tree) { // a Query is WASM-backed, so free it if we created it (a caller-supplied Query stays theirs) const ownQuery = typeof source === 'string'; const query = ownQuery ? this.createQuery(source) : source; try { return tree .flatMap(t => query.matches(t.rootNode)) .flatMap(m => m.captures); } finally { if (ownQuery) { query.delete(); } } } close() { this.parser.delete(); } } exports.TreeSitterExecutor = TreeSitterExecutor; //# sourceMappingURL=tree-sitter-executor.js.map