UNPKG

petcarescript

Version:

PetCareScript - A modern, expressive programming language designed for humans

112 lines (91 loc) 2.84 kB
/** * PetCareScript Environment * Manages variable scope */ class Environment { constructor(enclosing = null) { this.enclosing = enclosing; this.values = new Map(); } define(name, value) { const varName = this.extractName(name); this.values.set(varName, value); } ancestor(distance) { let environment = this; for (let i = 0; i < distance; i++) { if (!environment.enclosing) { throw new Error(`Cannot find ancestor at distance ${distance}`); } environment = environment.enclosing; } return environment; } getAt(distance, name) { const varName = this.extractName(name); return this.ancestor(distance).values.get(varName); } assignAt(distance, name, value) { const varName = this.extractName(name); this.ancestor(distance).values.set(varName, value); } get(name) { const varName = this.extractName(name); if (this.values.has(varName)) { return this.values.get(varName); } if (this.enclosing !== null) { return this.enclosing.get(varName); } throw new Error(`Undefined variable '${varName}'.`); } assign(name, value) { const varName = this.extractName(name); if (this.values.has(varName)) { this.values.set(varName, value); return; } if (this.enclosing !== null) { this.enclosing.assign(varName, value); return; } throw new Error(`Undefined variable '${varName}'.`); } // Helper method to extract name from various token/node formats extractName(name) { if (typeof name === 'string') { return name; } if (name && name.lexeme) { return name.lexeme; } if (name && name.name && name.name.lexeme) { return name.name.lexeme; } if (name && name.name) { return name.name; } throw new Error(`Cannot extract name from: ${JSON.stringify(name)}`); } // Debug method to see all variables in current scope getVariables() { return Array.from(this.values.keys()); } // Check if variable exists in current scope (not ancestors) hasLocal(name) { const varName = this.extractName(name); return this.values.has(varName); } // Check if variable exists in any scope has(name) { const varName = this.extractName(name); if (this.values.has(varName)) { return true; } if (this.enclosing !== null) { return this.enclosing.has(varName); } return false; } } module.exports = Environment;