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 CallContext* callcontext; 58 59 @disable this(); 60 61 this(CallContext* cc) 62 { 63 callcontext = cc; 64 } 65 66 int opApply(int delegate(ref Property) dg) 67 { 68 initialize(); 69 int result; 70 foreach(ref Property p; table) 71 { 72 result = dg(p); 73 if(result) 74 break; 75 } 76 return result; 77 } 78 79 int opApply(int delegate(ref Value, ref Property) dg) 80 { 81 initialize(); 82 int result; 83 84 foreach(Value key, ref Property p; table) 85 { 86 result = dg(key, p); 87 if(result) 88 break; 89 } 90 return result; 91 } 92 93 /******************************* 94 * Look up name and get its corresponding Property. 95 * Return null if not found. 96 */ 97 98 Property *getProperty(d_string name) 99 { 100 Value* v; 101 Property *p; 102 103 v = get(name, Value.calcHash(name)); 104 if(!v) 105 return null; 106 107 // Work backwards from &p->value to p 108 p = cast(Property *)(cast(char *)v - uint.sizeof /*Property.value.offsetof*/); 109 110 return p; 111 } 112 113 Value* get(Value* key, hash_t hash) 114 { 115 uint i; 116 Property *p; 117 PropTable *t; 118 119 //writefln("get(key = '%s', hash = x%x)", key.toString(), hash); 120 assert(key.toHash(null) == hash); 121 t = &this; 122 do 123 { 124 //writefln("\tt = %x", cast(uint)t); 125 t.initialize(); 126 //p = *key in t.table; 127 p = t.table.findExistingAlt(*key,hash); 128 129 if(p) 130 { 131 //TODO: what's that assert for? -- seems to run OK without it 132 //bombs with range violation otherwise! 133 /*try{ 134 assert(t.table[*key] == p); 135 }catch(Error e){ 136 writef("get(key = '%s', hash = x%x)", key.toString(), hash); 137 //writefln("\tfound"); 138 p.value.dump(); 139 }*/ 140 //p.value.dump(); 141 return &p.value; 142 } 143 t = t.previous; 144 } while(t); 145 //writefln("\tnot found"); 146 return null; // not found 147 } 148 149 Value* get(d_uint32 index) 150 { 151 //writefln("get(index = %d)", index); 152 Value key; 153 154 key.putVnumber(index); 155 return get(&key, Value.calcHash(index)); 156 } 157 158 Value* get(Identifier* id) 159 { 160 //writefln("get('%s', hash = x%x)", name, hash); 161 return get(&id.value, id.value.hash); 162 //return get(id.value.string, id.value.hash); 163 } 164 165 Value* get(d_string name, hash_t hash) 166 { 167 //writefln("get('%s', hash = x%x)", name, hash); 168 Value key; 169 170 key.putVstring(name); 171 return get(&key, hash); 172 } 173 174 /******************************* 175 * Determine if property exists for this object. 176 * The enumerable flag means the DontEnum attribute cannot be set. 177 */ 178 179 int hasownproperty(Value* key, int enumerable) 180 { 181 initialize(); 182 Property* p; 183 184 p = *key in table; 185 return p && (!enumerable || !(p.attributes & DontEnum)); 186 } 187 188 int hasproperty(Value* key) 189 { 190 initialize(); 191 return (*key in table) != null || (previous && previous.hasproperty(key)); 192 } 193 194 int hasproperty(d_string name) 195 { 196 Value v; 197 198 v.putVstring(name); 199 return hasproperty(&v); 200 } 201 202 Value* put(Value* key, hash_t hash, Value* value, uint attributes) 203 { 204 initialize(); 205 Property* p; 206 //writefln("table contains %d properties",table.length); 207 //writefln("put(key = %s, hash = x%x, value = %s, attributes = x%x)", key.toString(), hash, value.toString(), attributes); 208 //writefln("put(key = %s)", key.toString()); 209 210 //p = &table[*key]; 211 //version(none){ 212 //writeln(cast(void*)table); 213 //p = *key in table; 214 p = table.findExistingAlt(*key,hash); 215 216 217 if(p) 218 { 219 Lx: 220 if(attributes & DontOverride && p.value.vtype != V_REF_ERROR || 221 p.attributes & ReadOnly) 222 { 223 if(p.attributes & KeyWord) 224 return null; 225 return &vundefined; 226 } 227 228 PropTable* t = previous; 229 if(t) 230 { 231 do 232 { 233 Property* q; 234 t.initialize(); 235 //q = *key in t.table; 236 q = t.table.findExistingAlt(*key,hash); 237 if(q) 238 { 239 if(q.attributes & ReadOnly) 240 { 241 p.attributes |= ReadOnly; 242 return &vundefined; 243 } 244 break; 245 } 246 t = t.previous; 247 } while(t); 248 } 249 250 // Overwrite property with new value 251 Value.copy(&p.value, value); 252 p.attributes = (attributes & ~DontOverride) | (p.attributes & (DontDelete | DontEnum)); 253 return null; 254 } 255 else{ 256 //table[*key] = Property(attributes & ~DontOverride,*value); 257 auto v = Property(attributes & ~DontOverride,*value); 258 table.insertAlt(*key, v, hash); 259 return null; // success 260 } 261 } 262 263 Value* put(d_string name, Value* value, uint attributes) 264 { 265 Value key; 266 267 key.putVstring(name); 268 269 //writef("PropTable::put(%p, '%ls', hash = x%x)\n", this, d_string_ptr(name), key.toHash()); 270 return put(&key, Value.calcHash(name), value, attributes); 271 } 272 273 Value* put(d_uint32 index, Value* value, uint attributes) 274 { 275 Value key; 276 277 key.putVnumber(index); 278 279 //writef("PropTable::put(%d)\n", index); 280 return put(&key, Value.calcHash(index), value, attributes); 281 } 282 283 Value* put(d_uint32 index, d_string string, uint attributes) 284 { 285 Value key; 286 Value value; 287 288 key.putVnumber(index); 289 value.putVstring(string); 290 291 return put(&key, Value.calcHash(index), &value, attributes); 292 } 293 294 int canput(Value* key, hash_t hash) 295 { 296 initialize(); 297 Property *p; 298 PropTable *t; 299 300 t = &this; 301 do 302 { 303 //p = *key in t.table; 304 p = t.table.findExistingAlt(*key,hash); 305 if(p) 306 { 307 return (p.attributes & ReadOnly) 308 ? false : true; 309 } 310 t = t.previous; 311 } while(t); 312 return true; // success 313 } 314 315 int canput(d_string name) 316 { 317 Value v; 318 319 v.putVstring(name); 320 321 return canput(&v, v.hashString()); 322 } 323 324 int del(Value* key) 325 { 326 initialize(); 327 Property *p; 328 329 //writef("PropTable::del('%ls')\n", d_string_ptr(key.toString())); 330 p = *key in table; 331 if(p) 332 { 333 if(p.attributes & DontDelete) 334 return false; 335 table.remove(*key); 336 } 337 return true; // not found 338 } 339 340 int del(d_string name) 341 { 342 Value v; 343 344 v.putVstring(name); 345 346 //writef("PropTable::del('%ls')\n", d_string_ptr(name)); 347 return del(&v); 348 } 349 350 int del(d_uint32 index) 351 { 352 Value v; 353 354 v.putVnumber(index); 355 356 //writef("PropTable::del(%d)\n", index); 357 return del(&v); 358 } 359 void initialize() 360 { 361 if(!table) 362 table = new RandAA!(Value, Property)(callcontext); 363 } 364 } 365 366