Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 1x 1x 4x 1x 34x 34x 221x 221x 132x 221x 34x 34x 1x 34x 34x 34x 34x 18x 18x 18x 18x 18x 18x 18x 4x 18x 18x 18x 1x 18x 49x 49x 49x 49x 49x 49x 49x 342x 342x 137x 342x 34x 23x 34x 34x 34x 1x 34x 1x | /** * Universidad de La Laguna * Escuela Superior de Ingeniería y Tecnología * Grado en Ingeniería Informática * Procesadores de Lenguajes * * @author Juan Rodríguez Suárez * @since Mar 04 2024 * @desc Contains functions to analyze the scope of the program and the dependencies of the functions. */ const astTypes = require("ast-types"); const support = require("./support-lib.js"); // Build regexp matching the names of the support functions /factorial|power|min|max|.../ const FUNCTION_NAMES = Object.keys(support).map(n => n.replace(/[$*.^]/, '[$&]')); // Escape regexp special characters const patternIsSupport = new RegExp(FUNCTION_NAMES.join('|')); /** * @brief Builds the set of function dependencies * @param {object} dAst - The decorated AST * @returns {object} The decorated AST */ function dependencies(dAst) { let usedFunctions = new Set(); astTypes.visit(dAst.ast, { visitCallExpression(path) { const NODE = path.node; if (patternIsSupport.test(NODE.callee.name)) { usedFunctions.add(NODE.callee.name); } this.traverse(path); } }); dAst.dependencies = usedFunctions; return dAst; } /** * @brief Analyzes the scope of the program * @param {object} dAst - The decorated AST * @returns {object} The decorated AST */ const scopeAnalysis = (dAst) => { const Scope = require("./scope-class.js"); let scope = new Scope(null); // global scope let ast = dAst.ast; astTypes.visit(ast, { visitFunctionExpression(path) { let node = path.node; scope = new Scope(scope); // mark parameters as initialized const PARAMETERS = node.params; for (const PARAM of PARAMETERS) { scope.setAsInitialized(PARAM.name); } this.traverse(path); if (scope.length > 0) { // insert declarations at the beginning of the function node.body.body.unshift(scope.buildDeclaration()); } node.scope = scope; const NOT_DECLARED_MESSAGE = scope.notDeclaredMessage(); if (NOT_DECLARED_MESSAGE) { console.error('*** WARNING: ' + NOT_DECLARED_MESSAGE + ' in function scope ***\n'); } scope = scope.parent; }, visitAssignmentExpression(path) { const NODE = path.node; Eif (NODE.left.type === 'Identifier') { let name = NODE.left.name; Eif (name && !scope.has(name)) { Eif (!dAst.dependencies.has(name)) { scope.add(name); } } } this.traverse(path); }, visitIdentifier(path) { const NAME = path.node.name; if (/^[$]/.test(NAME) && !dAst.dependencies.has(NAME)) { scope.setAsUsed(NAME); } this.traverse(path); } }); if (scope.length > 0) { // insert declarations at the beginning of the program ast.body.unshift(scope.buildDeclaration()); } ast.scope = scope; const NOT_DECLARED_MESSAGE = scope.notDeclaredMessage(); if (NOT_DECLARED_MESSAGE) { console.error('*** WARNING: ' + NOT_DECLARED_MESSAGE + ' in global scope ***\n'); } return dAst; }; module.exports = { dependencies, scopeAnalysis } |