src/stdlib/Proxy.js
'use strict';
const Value = require('../Value');
const ObjectValue = require('../values/ObjectValue');
const EasyObjectValue = require('../values/EasyObjectValue');
const CompletionRecord = require('../CompletionRecord');
class ProxyClass extends ObjectValue {
*call(thiz, args, scope, ext) {
let asConstructor = ext && ext.asConstructor;
if ( !asConstructor ) {
return Value.fromNative(0);
}
thiz.target = args[0];
thiz.handler = args[1];
thiz.realm = scope.realm;
}
*makeThisForNew(realm) {
return new ProxyValue(realm);
}
}
class ProxyValue extends Value {
*handlerImplemented(w) {
let en = (yield * this.handler.inOperator(Value.fromNative(w))).toNative();
return !!en;
}
ref(name, ctxthis) {
return {
name: name,
object: this,
isVariable: false,
del: () => false, //Doesnt support being a generator yet.
getValue: () => this.get(name, s),
setValue: function(to, s) { return this.object.set(this.name, to, s); }
};
}
*invokeHandler(w, args) {
let fn = yield * this.handler.get(w);
return yield * fn.call(Value.under, args.map((x) => this.realm.fromNative(x)), this.realm.globalScope)
}
*get(name, realm, ctx) {
if ( yield * this.handlerImplemented('get') ) {
return yield * this.invokeHandler('get', [name]);
}
return yield * this.target.get(name, realm, ctx);
}
*set(name, value, realm, ctx) {
if ( yield * this.handlerImplemented('set') ) {
return yield * this.invokeHandler('set', [name, value]);
}
return yield * this.target.set(name, value, realm, ctx);
}
*inOperator(other) {
if ( yield * this.handlerImplemented('has') ) {
return yield * this.invokeHandler('has', [other]);
}
return yield * this.target.inOperator(other, realm, ctx);
}
*delete(name) {
if ( yield * this.handlerImplemented('delete') ) {
return yield * this.invokeHandler('delete', [other]);
}
return yield * this.target.delete(other, realm, ctx);
}
*call(thiz, args, scope, ext) {
let asConstructor = ext && ext.asConstructor;
let key = 'apply';
if ( asConstructor ) key = 'construct';
if ( yield * this.handlerImplemented(key) ) {
return yield * this.invokeHandler(key, args);
}
if ( !this.target.call ) return CompletionRecord.makeTypeError(scope.realm, "Base object not invokeable.");
else return yield * this.target.call(thiz, args, scope, ext);
}
*makeThisForNew(realm) {
return this.target.makeThisForNew(realm);
}
toNative() { return "[Proxy]"; }
}
module.exports = ProxyClass;