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