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.iterator;
20 
21 import std.algorithm.sorting;
22 
23 import dmdscript.script;
24 import dmdscript.dobject;
25 import dmdscript.value;
26 import dmdscript.property;
27 
28 Dobject getPrototype(Dobject o)
29 {
30     version(all)
31     {
32         return o.internal_prototype;    // use internal [[Prototype]]
33     }
34     else
35     {
36         // use "prototype"
37         Value *v;
38 
39         v = o.Get(TEXT_prototype);
40         if(!v || v.isPrimitive())
41             return null;
42         o = v.toObject();
43         return o;
44     }
45 }
46 
47 struct Iterator
48 {
49             Value[] keys;
50     size_t  keyindex;
51     Dobject o;
52     Dobject ostart;
53     CallContext* callcontext;
54 
55     debug
56     {
57         enum uint ITERATOR_VALUE = 0x1992836;
58         uint foo = ITERATOR_VALUE;
59     }
60 
61     invariant()
62     {
63         debug assert(foo == ITERATOR_VALUE);
64     }
65 
66     void ctor(CallContext* cc, Dobject o)
67     {
68         debug foo = ITERATOR_VALUE;
69         //writef("Iterator: o = %p, p = %p\n", o, p);
70         ostart = o;
71         this.o = o;
72         this.callcontext = cc;
73         keys = o.proptable.table.keys.sort!((a, b) => a.compare(cc, b) < 0).release;
74         keyindex = 0;
75     }
76 
77     Value *next()
78     {
79         Property* p;
80 
81         //writef("Iterator::done() p = %p\n", p);
82 
83         for(;; keyindex++)
84         {
85             while(keyindex == keys.length)
86             {
87                 destroy(keys);
88                 o = getPrototype(o);
89                 if(!o)
90                     return null;
91                 keys = o.proptable.table.keys.sort!((a, b) => a.compare(this.callcontext, b) < 0).release;
92                 keyindex = 0;
93             }
94             Value* key = &keys[keyindex];
95             p = *key in o.proptable.table;
96             if(!p)                      // if no longer in property table
97                 continue;
98             if(p.attributes & DontEnum)
99                 continue;
100             else
101             {
102                 // ECMA 12.6.3
103                 // Do not enumerate those properties in prototypes
104                 // that are overridden
105                 if(o != ostart)
106                 {
107                     for(Dobject ot = ostart; ot != o; ot = getPrototype(ot))
108                     {
109                         // If property p is in t, don't enumerate
110                         if(*key in ot.proptable.table)
111                             goto Lcontinue;
112                     }
113                 }
114                 keyindex++;
115                 return key; //&p.value;
116 
117                 Lcontinue:
118                 ;
119             }
120         }
121         assert(0);
122     }
123 }