1 /* Digital Mars DMDScript source code. 2 * Copyright (c) 2000-2002 by Chromium Communications 3 * D version Copyright (c) 2004-2010 by Digital Mars 4 * Distributed under the Boost Software License, Version 1.0. 5 * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 * written by Walter Bright 7 * http://www.digitalmars.com 8 * 9 * D2 port by Dmitry Olshansky 10 * 11 * DMDScript is implemented in the D Programming Language, 12 * http://www.digitalmars.com/d/ 13 * 14 * For a C++ implementation of DMDScript, including COM support, see 15 * http://www.digitalmars.com/dscript/cppscript.html 16 */ 17 18 19 module dmdscript.property; 20 21 import dmdscript.script; 22 import dmdscript.value; 23 import dmdscript.identifier; 24 25 import dmdscript.RandAA; 26 27 import core.stdc..string; 28 import std.stdio; 29 30 // attribute flags 31 enum 32 { 33 ReadOnly = 0x001, 34 DontEnum = 0x002, 35 DontDelete = 0x004, 36 Internal = 0x008, 37 Deleted = 0x010, 38 Locked = 0x020, 39 DontOverride = 0x040, 40 KeyWord = 0x080, 41 DebugFree = 0x100, // for debugging help 42 Instantiate = 0x200, // For COM named item namespace support 43 } 44 45 struct Property 46 { 47 uint attributes; 48 49 Value value; 50 } 51 52 /*********************************** PropTable *********************/ 53 struct PropTable 54 { 55 RandAA!(Value, Property) table; 56 PropTable* previous; 57 58 int opApply(int delegate(ref Property) dg) 59 { 60 initialize(); 61 int result; 62 foreach(ref Property p; table) 63 { 64 result = dg(p); 65 if(result) 66 break; 67 } 68 return result; 69 } 70 71 int opApply(int delegate(ref Value, ref Property) dg) 72 { 73 initialize(); 74 int result; 75 76 foreach(Value key, ref Property p; table) 77 { 78 result = dg(key, p); 79 if(result) 80 break; 81 } 82 return result; 83 } 84 85 /******************************* 86 * Look up name and get its corresponding Property. 87 * Return null if not found. 88 */ 89 90 Property *getProperty(d_string name) 91 { 92 Value* v; 93 Property *p; 94 95 v = get(name, Value.calcHash(name)); 96 if(!v) 97 return null; 98 99 // Work backwards from &p->value to p 100 p = cast(Property *)(cast(char *)v - uint.sizeof /*Property.value.offsetof*/); 101 102 return p; 103 } 104 105 Value* get(Value* key, hash_t hash) 106 { 107 uint i; 108 Property *p; 109 PropTable *t; 110 111 //writefln("get(key = '%s', hash = x%x)", key.toString(), hash); 112 assert(key.toHash() == hash); 113 t = &this; 114 do 115 { 116 //writefln("\tt = %x", cast(uint)t); 117 t.initialize(); 118 //p = *key in t.table; 119 p = t.table.findExistingAlt(*key,hash); 120 121 if(p) 122 { 123 //TODO: what's that assert for? -- seems to run OK without it 124 //bombs with range violation otherwise! 125 /*try{ 126 assert(t.table[*key] == p); 127 }catch(Error e){ 128 writef("get(key = '%s', hash = x%x)", key.toString(), hash); 129 //writefln("\tfound"); 130 p.value.dump(); 131 }*/ 132 //p.value.dump(); 133 return &p.value; 134 } 135 t = t.previous; 136 } while(t); 137 //writefln("\tnot found"); 138 return null; // not found 139 } 140 141 Value* get(d_uint32 index) 142 { 143 //writefln("get(index = %d)", index); 144 Value key; 145 146 key.putVnumber(index); 147 return get(&key, Value.calcHash(index)); 148 } 149 150 Value* get(Identifier* id) 151 { 152 //writefln("get('%s', hash = x%x)", name, hash); 153 return get(&id.value, id.value.hash); 154 //return get(id.value.string, id.value.hash); 155 } 156 157 Value* get(d_string name, hash_t hash) 158 { 159 //writefln("get('%s', hash = x%x)", name, hash); 160 Value key; 161 162 key.putVstring(name); 163 return get(&key, hash); 164 } 165 166 /******************************* 167 * Determine if property exists for this object. 168 * The enumerable flag means the DontEnum attribute cannot be set. 169 */ 170 171 int hasownproperty(Value* key, int enumerable) 172 { 173 initialize(); 174 Property* p; 175 176 p = *key in table; 177 return p && (!enumerable || !(p.attributes & DontEnum)); 178 } 179 180 int hasproperty(Value* key) 181 { 182 initialize(); 183 return (*key in table) != null || (previous && previous.hasproperty(key)); 184 } 185 186 int hasproperty(d_string name) 187 { 188 Value v; 189 190 v.putVstring(name); 191 return hasproperty(&v); 192 } 193 194 Value* put(Value* key, hash_t hash, Value* value, uint attributes) 195 { 196 initialize(); 197 Property* p; 198 //writefln("table contains %d properties",table.length); 199 //writefln("put(key = %s, hash = x%x, value = %s, attributes = x%x)", key.toString(), hash, value.toString(), attributes); 200 //writefln("put(key = %s)", key.toString()); 201 202 //p = &table[*key]; 203 //version(none){ 204 //writeln(cast(void*)table); 205 //p = *key in table; 206 p = table.findExistingAlt(*key,hash); 207 208 209 if(p) 210 { 211 Lx: 212 if(attributes & DontOverride && p.value.vtype != V_REF_ERROR || 213 p.attributes & ReadOnly) 214 { 215 if(p.attributes & KeyWord) 216 return null; 217 return &vundefined; 218 } 219 220 PropTable* t = previous; 221 if(t) 222 { 223 do 224 { 225 Property* q; 226 t.initialize(); 227 //q = *key in t.table; 228 q = t.table.findExistingAlt(*key,hash); 229 if(q) 230 { 231 if(q.attributes & ReadOnly) 232 { 233 p.attributes |= ReadOnly; 234 return &vundefined; 235 } 236 break; 237 } 238 t = t.previous; 239 } while(t); 240 } 241 242 // Overwrite property with new value 243 Value.copy(&p.value, value); 244 p.attributes = (attributes & ~DontOverride) | (p.attributes & (DontDelete | DontEnum)); 245 return null; 246 } 247 else{ 248 //table[*key] = Property(attributes & ~DontOverride,*value); 249 auto v = Property(attributes & ~DontOverride,*value); 250 table.insertAlt(*key, v, hash); 251 return null; // success 252 } 253 } 254 255 Value* put(d_string name, Value* value, uint attributes) 256 { 257 Value key; 258 259 key.putVstring(name); 260 261 //writef("PropTable::put(%p, '%ls', hash = x%x)\n", this, d_string_ptr(name), key.toHash()); 262 return put(&key, Value.calcHash(name), value, attributes); 263 } 264 265 Value* put(d_uint32 index, Value* value, uint attributes) 266 { 267 Value key; 268 269 key.putVnumber(index); 270 271 //writef("PropTable::put(%d)\n", index); 272 return put(&key, Value.calcHash(index), value, attributes); 273 } 274 275 Value* put(d_uint32 index, d_string string, uint attributes) 276 { 277 Value key; 278 Value value; 279 280 key.putVnumber(index); 281 value.putVstring(string); 282 283 return put(&key, Value.calcHash(index), &value, attributes); 284 } 285 286 int canput(Value* key, hash_t hash) 287 { 288 initialize(); 289 Property *p; 290 PropTable *t; 291 292 t = &this; 293 do 294 { 295 //p = *key in t.table; 296 p = t.table.findExistingAlt(*key,hash); 297 if(p) 298 { 299 return (p.attributes & ReadOnly) 300 ? false : true; 301 } 302 t = t.previous; 303 } while(t); 304 return true; // success 305 } 306 307 int canput(d_string name) 308 { 309 Value v; 310 311 v.putVstring(name); 312 313 return canput(&v, v.toHash()); 314 } 315 316 int del(Value* key) 317 { 318 initialize(); 319 Property *p; 320 321 //writef("PropTable::del('%ls')\n", d_string_ptr(key.toString())); 322 p = *key in table; 323 if(p) 324 { 325 if(p.attributes & DontDelete) 326 return false; 327 table.remove(*key); 328 } 329 return true; // not found 330 } 331 332 int del(d_string name) 333 { 334 Value v; 335 336 v.putVstring(name); 337 338 //writef("PropTable::del('%ls')\n", d_string_ptr(name)); 339 return del(&v); 340 } 341 342 int del(d_uint32 index) 343 { 344 Value v; 345 346 v.putVnumber(index); 347 348 //writef("PropTable::del(%d)\n", index); 349 return del(&v); 350 } 351 void initialize() 352 { 353 if(!table) 354 table = new RandAA!(Value, Property); 355 } 356 } 357 358