src/Scope.js
'use strict';
const PropertyDescriptor = require('./values/PropertyDescriptor');
const Value = require('./Value');
const ObjectValue = require('./values/ObjectValue');
class Scope {
constructor(realm) {
this.parent = null;
this.object = new ObjectValue(realm);
this.strict = false;
this.realm = realm;
this.global = this;
this.top = this;
this.writeTo = this.object;
this.writeToBlock = this.object;
this.thiz = null;
}
/**
* @param {string} name - Identifier to retreive
* @returns {Value}
*/
get(name) {
//Fast property access in the common case.
let prop = this.object.properties[name];
if ( !prop ) return Value.undef;
if ( !prop.getter ) return prop.value;
return this.object.getImmediate(name);
}
ref(name) {
var vhar = this.object.properties[name];
if (!vhar) return undefined;
var that = this;
var o = {
setValue: vhar.setValue.bind(vhar, this),
getValue: vhar.getValue.bind(vhar, this),
isVariable: !!vhar.variable
};
if ( this.global.object.properties[name] === vhar ) {
o.del = (s) => this.global.object.delete(name,s);
}
return o;
}
add(name, value) {
this.writeTo.setImmediate(name, value);
this.writeToBlock.properties[name].variable = true;
}
addBlock(name, value) {
this.writeToBlock.setImmediate(name, value);
this.writeToBlock.properties[name].variable = true;
}
addConst(name, value) {
this.set(name, value);
this.writeToBlock.properties[name].writable = false;
this.writeToBlock.properties[name].configurable = false;
}
/**
* Set the identifier in its nearest scope, or create a global.
* @param {string} name - Identifier to retreive
* @param {Value} value - New vaalue of variable
*/
set(name, value) {
return this.put(name, value);
}
has(name) {
return this.object.has(name);
}
/**
* Set the identifier in its nearest scope, or create a global.
* @param {string} name - Identifier to retreive
* @param {Value} value - New vaalue of variable
* @param {Scope} s - Code scope to run setter functions in
*/
put(name, value, s) {
let variable = this.object.properties[name];
if ( variable ) {
return variable.setValue(this.object, value, s);
}
var v = new PropertyDescriptor(value, this);
this.writeTo.properties[name] = v;
return Value.undef.fastGen();
}
createChild() {
let child = new Scope(this.realm);
child.object.eraseAndSetPrototype(this.object);
child.parent = this;
child.strict = this.strict;
child.global = this.global;
child.realm = this.realm;
child.top = this.top;
return child;
}
createBlockChild() {
let c = this.createChild();
c.thiz = this.thiz;
c.writeTo = this.writeTo;
c.parent = this.parent;
return c;
}
fromNative(value, x) {
return this.realm.fromNative(value, x);
}
getVariableNames() {
let list = [];
for ( var o in this.object.properties ) list.push(o);
return list;
}
}
module.exports = Scope;