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