mirror of
				https://github.com/tc39/test262.git
				synced 2025-10-25 17:53:53 +02:00 
			
		
		
		
	sourceRevisionAtLastExport: 33f2fb0e53d135f0ee17cfccd9d993eb2a6f47de targetRevisionAtLastExport: 31340cbd9add103f586d501b0c3354b7b182abc0
		
			
				
	
	
		
			309 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Copyright 2011 the V8 project authors. All rights reserved.
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //     * Redistributions of source code must retain the above copyright
 | |
| //       notice, this list of conditions and the following disclaimer.
 | |
| //     * Redistributions in binary form must reproduce the above
 | |
| //       copyright notice, this list of conditions and the following
 | |
| //       disclaimer in the documentation and/or other materials provided
 | |
| //       with the distribution.
 | |
| //     * Neither the name of Google Inc. nor the names of its
 | |
| //       contributors may be used to endorse or promote products derived
 | |
| //       from this software without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| 
 | |
| // A simple membrane. Adapted from:
 | |
| // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane
 | |
| 
 | |
| function createSimpleMembrane(target) {
 | |
|   let enabled = true;
 | |
| 
 | |
|   function wrap(obj) {
 | |
|     if (obj !== Object(obj)) return obj;
 | |
| 
 | |
|     let handler = new Proxy({}, {get: function(_, key) {
 | |
|       if (!enabled) throw new Error("disabled");
 | |
|       switch (key) {
 | |
|       case "apply":
 | |
|         return (_, that, args) => {
 | |
|           try {
 | |
|             return wrap(Reflect.apply(
 | |
|                 obj, wrap(that), args.map((x) => wrap(x))));
 | |
|           } catch(e) {
 | |
|             throw wrap(e);
 | |
|           }
 | |
|         }
 | |
|       case "construct":
 | |
|         return (_, args, newt) => {
 | |
|           try {
 | |
|             return wrap(Reflect.construct(
 | |
|                 obj, args.map((x) => wrap(x)), wrap(newt)));
 | |
|           } catch(e) {
 | |
|             throw wrap(e);
 | |
|           }
 | |
|         }
 | |
|       default:
 | |
|         return (_, ...args) => {
 | |
|           try {
 | |
|             return wrap(Reflect[key](obj, ...(args.map(wrap))));
 | |
|           } catch(e) {
 | |
|             throw wrap(e);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }});
 | |
| 
 | |
|     return new Proxy(obj, handler);
 | |
|   }
 | |
| 
 | |
|   const gate = Object.freeze({
 | |
|     enable: () => enabled = true,
 | |
|     disable: () => enabled = false
 | |
|   });
 | |
| 
 | |
|   return Object.freeze({
 | |
|     wrapper: wrap(target),
 | |
|     gate: gate
 | |
|   });
 | |
| }
 | |
| 
 | |
| 
 | |
| // Test the simple membrane.
 | |
| {
 | |
|   var o = {
 | |
|     a: 6,
 | |
|     b: {bb: 8},
 | |
|     f: function(x) { return x },
 | |
|     g: function(x) { return x.a },
 | |
|     h: function(x) { this.q = x }
 | |
|   };
 | |
|   o[2] = {c: 7};
 | |
|   var m = createSimpleMembrane(o);
 | |
|   var w = m.wrapper;
 | |
|   var f = w.f;
 | |
|   var x = f(66);
 | |
|   var x = f({a: 1});
 | |
|   var x = w.f({a: 1});
 | |
|   var a = x.a;
 | |
|   assertEquals(6, w.a);
 | |
|   assertEquals(8, w.b.bb);
 | |
|   assertEquals(7, w[2]["c"]);
 | |
|   assertEquals(undefined, w.c);
 | |
|   assertEquals(1, w.f(1));
 | |
|   assertEquals(1, w.f({a: 1}).a);
 | |
|   assertEquals(2, w.g({a: 2}));
 | |
|   assertEquals(3, (w.r = {a: 3}).a);
 | |
|   assertEquals(3, w.r.a);
 | |
|   assertEquals(3, o.r.a);
 | |
|   w.h(3);
 | |
|   assertEquals(3, w.q);
 | |
|   assertEquals(3, o.q);
 | |
|   assertEquals(4, (new w.h(4)).q);
 | |
| 
 | |
|   var wb = w.b;
 | |
|   var wr = w.r;
 | |
|   var wf = w.f;
 | |
|   var wf3 = w.f(3);
 | |
|   var wfx = w.f({a: 6});
 | |
|   var wgx = w.g({a: {aa: 7}});
 | |
|   var wh4 = new w.h(4);
 | |
|   m.gate.disable();
 | |
|   assertEquals(3, wf3);
 | |
|   assertThrows(function() { w.a }, Error);
 | |
|   assertThrows(function() { w.r }, Error);
 | |
|   assertThrows(function() { w.r = {a: 4} }, Error);
 | |
|   assertThrows(function() { o.r.a }, Error);
 | |
|   assertEquals("object", typeof o.r);
 | |
|   assertEquals(5, (o.r = {a: 5}).a);
 | |
|   assertEquals(5, o.r.a);
 | |
|   assertThrows(function() { w[1] }, Error);
 | |
|   assertThrows(function() { w.c }, Error);
 | |
|   assertThrows(function() { wb.bb }, Error);
 | |
|   assertThrows(function() { wr.a }, Error);
 | |
|   assertThrows(function() { wf(4) }, Error);
 | |
|   assertThrows(function() { wfx.a }, Error);
 | |
|   assertThrows(function() { wgx.aa }, Error);
 | |
|   assertThrows(function() { wh4.q }, Error);
 | |
| 
 | |
|   m.gate.enable();
 | |
|   assertEquals(6, w.a);
 | |
|   assertEquals(5, w.r.a);
 | |
|   assertEquals(5, o.r.a);
 | |
|   assertEquals(7, w.r = 7);
 | |
|   assertEquals(7, w.r);
 | |
|   assertEquals(7, o.r);
 | |
|   assertEquals(8, w.b.bb);
 | |
|   assertEquals(7, w[2]["c"]);
 | |
|   assertEquals(undefined, w.c);
 | |
|   assertEquals(8, wb.bb);
 | |
|   assertEquals(3, wr.a);
 | |
|   assertEquals(4, wf(4));
 | |
|   assertEquals(3, wf3);
 | |
|   assertEquals(6, wfx.a);
 | |
|   assertEquals(7, wgx.aa);
 | |
|   assertEquals(4, wh4.q);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| // An identity-preserving membrane. Adapted from:
 | |
| // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving_membrane
 | |
| 
 | |
| function createMembrane(target) {
 | |
|   const wet2dry = 0;
 | |
|   const dry2wet = 1;
 | |
| 
 | |
|   function flip(dir) { return (dir + 1) % 2 }
 | |
| 
 | |
|   let maps = [new WeakMap(), new WeakMap()];
 | |
| 
 | |
|   let revoked = false;
 | |
| 
 | |
|   function wrap(dir, obj) {
 | |
|     if (obj !== Object(obj)) return obj;
 | |
| 
 | |
|     let wrapper = maps[dir].get(obj);
 | |
|     if (wrapper) return wrapper;
 | |
| 
 | |
|     let handler = new Proxy({}, {get: function(_, key) {
 | |
|       if (revoked) throw new Error("revoked");
 | |
|       switch (key) {
 | |
|       case "apply":
 | |
|         return (_, that, args) => {
 | |
|           try {
 | |
|             return wrap(dir, Reflect.apply(
 | |
|                 obj, wrap(flip(dir), that),
 | |
|                 args.map((x) => wrap(flip(dir), x))));
 | |
|           } catch(e) {
 | |
|             throw wrap(dir, e);
 | |
|           }
 | |
|         }
 | |
|       case "construct":
 | |
|         return (_, args, newt) => {
 | |
|           try {
 | |
|             return wrap(dir, Reflect.construct(
 | |
|                 obj, args.map((x) => wrap(flip(dir), x)),
 | |
|                 wrap(flip(dir), newt)));
 | |
|           } catch(e) {
 | |
|             throw wrap(dir, e);
 | |
|           }
 | |
|         }
 | |
|       default:
 | |
|         return (_, ...args) => {
 | |
|           try {
 | |
|             return wrap(dir, Reflect[key](
 | |
|                 obj, ...(args.map((x) => wrap(flip(dir), x)))))
 | |
|           } catch(e) {
 | |
|             throw wrap(dir, e);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }});
 | |
| 
 | |
|     wrapper = new Proxy(obj, handler);
 | |
|     maps[dir].set(obj, wrapper);
 | |
|     maps[flip(dir)].set(wrapper, obj);
 | |
|     return wrapper;
 | |
|   }
 | |
| 
 | |
|   const gate = Object.freeze({
 | |
|     revoke: () => revoked = true
 | |
|   });
 | |
| 
 | |
|   return Object.freeze({
 | |
|     wrapper: wrap(wet2dry, target),
 | |
|     gate: gate
 | |
|   });
 | |
| }
 | |
| 
 | |
| 
 | |
| // Test the identity-preserving membrane.
 | |
| {
 | |
|   var receiver
 | |
|   var argument
 | |
|   var o = {
 | |
|     a: 6,
 | |
|     b: {bb: 8},
 | |
|     f: function(x) {receiver = this; argument = x; return x},
 | |
|     g: function(x) {receiver = this; argument = x; return x.a},
 | |
|     h: function(x) {receiver = this; argument = x; this.q = x},
 | |
|     s: function(x) {receiver = this; argument = x; this.x = {y: x}; return this}
 | |
|   }
 | |
|   o[2] = {c: 7}
 | |
|   var m = createMembrane(o)
 | |
|   var w = m.wrapper
 | |
|   var f = w.f
 | |
|   var x = f(66)
 | |
|   var x = f({a: 1})
 | |
|   var x = w.f({a: 1})
 | |
|   var a = x.a
 | |
|   assertEquals(6, w.a)
 | |
|   assertEquals(8, w.b.bb)
 | |
|   assertEquals(7, w[2]["c"])
 | |
|   assertEquals(undefined, w.c)
 | |
|   assertEquals(1, w.f(1))
 | |
|   assertSame(o, receiver)
 | |
|   assertEquals(1, w.f({a: 1}).a)
 | |
|   assertSame(o, receiver)
 | |
|   assertEquals(2, w.g({a: 2}))
 | |
|   assertSame(o, receiver)
 | |
|   assertSame(w, w.f(w))
 | |
|   assertSame(o, receiver)
 | |
|   assertSame(o, argument)
 | |
|   assertSame(o, w.f(o))
 | |
|   assertSame(o, receiver)
 | |
|   // Note that argument !== o, since o isn't dry, so gets wrapped wet again.
 | |
|   assertEquals(3, (w.r = {a: 3}).a)
 | |
|   assertEquals(3, w.r.a)
 | |
|   assertEquals(3, o.r.a)
 | |
|   w.h(3)
 | |
|   assertEquals(3, w.q)
 | |
|   assertEquals(3, o.q)
 | |
|   assertEquals(4, (new w.h(4)).q)
 | |
|   assertEquals(5, w.s(5).x.y)
 | |
|   assertSame(o, receiver)
 | |
| 
 | |
|   var wb = w.b
 | |
|   var wr = w.r
 | |
|   var wf = w.f
 | |
|   var wf3 = w.f(3)
 | |
|   var wfx = w.f({a: 6})
 | |
|   var wgx = w.g({a: {aa: 7}})
 | |
|   var wh4 = new w.h(4)
 | |
|   var ws5 = w.s(5)
 | |
|   var ws5x = ws5.x
 | |
|   m.gate.revoke()
 | |
|   assertEquals(3, wf3)
 | |
|   assertThrows(function() { w.a }, Error)
 | |
|   assertThrows(function() { w.r }, Error)
 | |
|   assertThrows(function() { w.r = {a: 4} }, Error)
 | |
|   assertThrows(function() { o.r.a }, Error)
 | |
|   assertEquals("object", typeof o.r)
 | |
|   assertEquals(5, (o.r = {a: 5}).a)
 | |
|   assertEquals(5, o.r.a)
 | |
|   assertThrows(function() { w[1] }, Error)
 | |
|   assertThrows(function() { w.c }, Error)
 | |
|   assertThrows(function() { wb.bb }, Error)
 | |
|   assertEquals(3, wr.a)
 | |
|   assertThrows(function() { wf(4) }, Error)
 | |
|   assertEquals(6, wfx.a)
 | |
|   assertEquals(7, wgx.aa)
 | |
|   assertThrows(function() { wh4.q }, Error)
 | |
|   assertThrows(function() { ws5.x }, Error)
 | |
|   assertThrows(function() { ws5x.y }, Error)
 | |
| }
 |