1 The `proto()` function retrievs or sets the prototype of the given object 2 or resource value. 3 4 Throws an exception if given value does not support setting prototypes. 5 6 When invoked with one argument, returns the prototype of the given value 7 (if any). 8 9 When invoked with two arguments, returns the given value. 10 11 -- Testcase -- 12 {% 13 let fs = require("fs"); 14 15 // create a "class instance" by attaching a function dictionary to 16 // a plain object. 17 let obj = proto({}, { 18 greeting: function(name) { 19 printf("Hello, %s!\n", name); 20 } 21 }); 22 23 // accessing a property on `obj` will look up the prototype chain 24 // if the object itself does not have it 25 obj.greeting("World"); 26 27 printf("%.J\n", [ 28 // retrieve prototype of `fs.file` resource 29 proto(fs.stdout), 30 31 // retrieve prototype of `obj` 32 proto(obj) 33 ]); 34 %} 35 -- End -- 36 37 -- Expect stdout -- 38 Hello, World! 39 [ 40 { 41 "ioctl": "function ioctl(...) { [native code] }", 42 "lock": "function lock(...) { [native code] }", 43 "truncate": "function truncate(...) { [native code] }", 44 "isatty": "function isatty(...) { [native code] }", 45 "error": "function error(...) { [native code] }", 46 "fileno": "function fileno(...) { [native code] }", 47 "flush": "function flush(...) { [native code] }", 48 "close": "function close(...) { [native code] }", 49 "tell": "function tell(...) { [native code] }", 50 "seek": "function seek(...) { [native code] }", 51 "write": "function write(...) { [native code] }", 52 "read": "function read(...) { [native code] }" 53 }, 54 { 55 "greeting": "function(name) { ... }" 56 } 57 ] 58 -- End -- 59 60 61 62 Passing an invalid value throws an exception. 63 64 -- Testcase -- 65 {% 66 proto("inval", {}); 67 %} 68 -- End -- 69 70 -- Expect stderr -- 71 Type error: Passed value is neither a prototype, resource or object 72 In line 2, byte 19: 73 74 ` proto("inval", {});` 75 ~~~~~~~~~~~~~~~~~^~ 76 77 78 -- End -- 79 80 -- Testcase -- 81 {% 82 proto({}, "inval"); 83 %} 84 -- End -- 85 86 -- Expect stderr -- 87 Type error: Passed value is neither a prototype, resource or object 88 In line 2, byte 19: 89 90 ` proto({}, "inval");` 91 ~~~~~~~~~~~~~~~~~^~ 92 93 94 -- End -- 95 96 97 Setting the prototype of a value to itself is rejected, as it would 98 create a circular prototype chain causing endless loops in lookups. 99 100 -- Testcase -- 101 {% 102 let a = {}; 103 proto(a, a); 104 %} 105 -- End -- 106 107 -- Expect stderr -- 108 Type error: Cannot set circular prototype 109 In line 3, byte 12: 110 111 ` proto(a, a);` 112 ~~~~~~~~~~^~ 113 114 115 -- End -- 116 117 118 Setting the prototype of a value to a value in its own prototype chain 119 is rejected as well. 120 121 -- Testcase -- 122 {% 123 let a = {}; 124 let b = {}; 125 126 proto(a, b); 127 proto(b, a); 128 %} 129 -- End -- 130 131 -- Expect stderr -- 132 Type error: Cannot set circular prototype 133 In line 6, byte 12: 134 135 ` proto(b, a);` 136 ~~~~~~~~~~^~ 137 138 139 -- End -- 140 141 142 Longer circular chains are rejected as well. 143 144 -- Testcase -- 145 {% 146 let a = {}; 147 let b = {}; 148 let c = {}; 149 150 proto(a, b); 151 proto(b, c); 152 proto(c, a); 153 %} 154 -- End -- 155 156 -- Expect stderr -- 157 Type error: Cannot set circular prototype 158 In line 8, byte 12: 159 160 ` proto(c, a);` 161 ~~~~~~~~~~^~ 162 163 164 -- End -- 165 166 167 Reassigning a prototype to a value that is not in its chain remains 168 allowed, including pointing at a former ancestor. 169 170 -- Testcase -- 171 {% 172 let a = {}; 173 let b = { x: 1 }; 174 let c = { y: 2 }; 175 176 proto(a, b); 177 proto(b, c); 178 179 // a -> b -> c, pointing a at c does not create a cycle 180 proto(a, c); 181 182 // b is no longer in a's chain, so a.x is null but a.y resolves 183 printf("%.J\n", [ a.x, a.y ]); 184 %} 185 -- End -- 186 187 -- Expect stdout -- 188 [ 189 null, 190 2 191 ] 192 -- End -- 193 194 195 Setting a prototype takes exactly one reference on it, which the value 196 releases when it is freed or given another prototype. 197 198 -- Testcase -- 199 {% 200 let getinfo = require("debug").getinfo; 201 let p = { x: 1 }; 202 let base = getinfo(p).refcount; 203 let refs = () => getinfo(p).refcount - base; 204 let counts = {}; 205 206 for (let i = 0; i < 100; i++) 207 proto({}, p); 208 209 counts.discarded = refs(); 210 211 let held = []; 212 213 for (let i = 0; i < 10; i++) 214 push(held, proto({}, p)); 215 216 counts.held = refs(); 217 218 held = null; 219 counts.released = refs(); 220 221 let a = proto({}, p); 222 223 proto(a, { y: 2 }); 224 counts.reassigned = refs(); 225 226 let c = proto({}, p); 227 let before = getinfo(c).refcount; 228 229 try { 230 proto(p, c); 231 } 232 catch (e) { 233 counts.rejected = getinfo(c).refcount - before; 234 } 235 236 printf("%.J\n", counts); 237 %} 238 -- End -- 239 240 -- Expect stdout -- 241 { 242 "discarded": 0, 243 "held": 10, 244 "released": 0, 245 "reassigned": 0, 246 "rejected": 0 247 } 248 -- End -- 249 250 251 Setting the prototype of a resource with an own prototype releases the 252 previous one. 253 254 -- Testcase -- 255 {% 256 let ffi; 257 258 try { 259 ffi = require("ffi"); 260 } 261 catch (e) { 262 exit(77); 263 } 264 265 let getinfo = require("debug").getinfo; 266 let p = { x: 1 }; 267 let q = { y: 2 }; 268 let base = getinfo(p).refcount; 269 let counts = {}; 270 271 proto(ffi.C, p); 272 counts.held = getinfo(p).refcount - base; 273 274 proto(ffi.C, q); 275 counts.released = getinfo(p).refcount - base; 276 counts.current = (proto(ffi.C) == q); 277 278 printf("%.J\n", counts); 279 %} 280 -- End -- 281 282 -- Expect stdout -- 283 { 284 "held": 1, 285 "released": 0, 286 "current": true 287 } 288 -- End --
This page was automatically generated by LXR 0.3.1. • OpenWrt