All files scope-class.js

87.09% Statements 27/31
62.5% Branches 5/8
83.33% Functions 10/12
85.71% Lines 24/28

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        1x 1x             36x 36x 36x 36x               41x 41x               5x               151x                 109x               21x                 52x 3x                 36x 36x 49x 49x   36x               36x 36x         36x               36x       1x
const {
  buildIdentifier,
  buildVariableDeclaration,
  buildVariableDeclarator,
} = require('./ast-build');
const { difference } = require('./utils.js');
 
/**
 * Represents a scope in a program.
 */
class Scope {
  constructor(parent) {
    this.parent = parent;
    this.initialized = new Set();
    this.used = new Set();
    this.VarDeclarators = [];
  }
 
  /**
   * Adds a variable to the scope.
   * @param {string} name - The name of the variable.
   */
  add(name) {
    this.initialized.add(name);
    this.VarDeclarators.push(buildVariableDeclarator(buildIdentifier(name)));
  }
 
  /**
   * Sets a variable as initialized in the scope.
   * @param {string} name - The name of the variable.
   */
  setAsInitialized(name) {
    this.initialized.add(name);
  }
 
  /**
   * Sets a variable as used in the scope.
   * @param {string} name - The name of the variable.
   */
  setAsUsed(name) {
    this.used.add(name);
  }
 
  /**
   * Checks if a variable is declared in the scope.
   * @param {string} name - The name of the variable.
   * @returns {boolean} - True if the variable is declared, false otherwise.
   */
  has(name) {
    return this.initialized.has(name);
  }
 
  /**
   * Builds the variable declaration for the scope.
   * @returns {VariableDeclaration} - The built variable declaration.
   */
  buildDeclaration() {
    return buildVariableDeclaration(this.VarDeclarators);
  }
 
  /**
   * Looks up a variable in the scope and its parent scopes.
   * @param {string} name - The name of the variable.
   * @returns {Scope|null} - The scope where the variable is declared, or null if not found.
   */
  lookup(name) {
    if (this.has(name)) return this;
    Eif (this.parent) return this.parent.lookup(name);
    return null;
  }
 
  /**
   * Finds variables that are used but not declared in the scope.
   * @returns {Set<string>} - The set of not declared variables.
   */
  notDeclared() { 
    let notDeclared = difference(this.used, this.initialized);
    for(let v of this.used) {
      let s = this.lookup(v);
      Eif (s) notDeclared.delete(v);
    }
    return notDeclared;
  }
 
  /**
   * Generates a message for not declared variables in the scope.
   * @returns {string|null} - The message for not declared variables, or null if all variables are declared.
   */
  notDeclaredMessage() {
    let d = this.notDeclared();
    Iif (d.size > 0) { 
      return Array.from(d)
         .map(x => x.replace(/^[$]/, ''))
         .map(x => `Not declared variable '${x}'`).join(',');
    }
    return null;
  }
 
  /**
   * Gets the number of variable declarators in the scope.
   * @returns {number} - The number of variable declarators.
   */
  get length() {
    return this.VarDeclarators.length;
  }
}
 
module.exports = Scope;