Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsiter.h
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=78:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 #ifndef jsiter_h___
41 #define jsiter_h___
42
43 /*
44  * JavaScript iterators.
45  */
46 #include "jscntxt.h"
47 #include "jsprvtd.h"
48 #include "jspubtd.h"
49 #include "jsversion.h"
50
51 /*
52  * NB: these flag bits are encoded into the bytecode stream in the immediate
53  * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's
54  * JSXDR_BYTECODE_VERSION.
55  */
56 #define JSITER_ENUMERATE  0x1   /* for-in compatible hidden default iterator */
57 #define JSITER_FOREACH    0x2   /* return [key, value] pair rather than key */
58 #define JSITER_KEYVALUE   0x4   /* destructuring for-in wants [key, value] */
59 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
60 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
61
62 /*
63  * For cacheable native iterators, whether the iterator is currently active.
64  * Not serialized by XDR.
65  */
66 #define JSITER_ACTIVE       0x1000
67 #define JSITER_UNREUSABLE   0x2000
68
69 namespace js {
70
71 struct NativeIterator {
72     JSObject  *obj;
73     jsid      *props_array;
74     jsid      *props_cursor;
75     jsid      *props_end;
76     uint32    *shapes_array;
77     uint32    shapes_length;
78     uint32    shapes_key;
79     uint32    flags;
80     JSObject  *next;  /* Forms cx->enumerators list, garbage otherwise. */
81
82     bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
83
84     inline jsid *begin() const {
85         return props_array;
86     }
87
88     inline jsid *end() const {
89         return props_end;
90     }
91
92     size_t numKeys() const {
93         return end() - begin();
94     }
95
96     jsid *current() const {
97         JS_ASSERT(props_cursor < props_end);
98         return props_cursor;
99     }
100
101     void incCursor() {
102         props_cursor = props_cursor + 1;
103     }
104
105     static NativeIterator *allocateIterator(JSContext *cx, uint32 slength,
106                                             const js::AutoIdVector &props);
107     void init(JSObject *obj, uintN flags, uint32 slength, uint32 key);
108
109     void mark(JSTracer *trc);
110 };
111
112 bool
113 VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap);
114
115 JS_FRIEND_API(bool)
116 GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector *props);
117
118 bool
119 GetIterator(JSContext *cx, JSObject *obj, uintN flags, js::Value *vp);
120
121 bool
122 VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
123
124 bool
125 VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
126
127 /*
128  * Creates either a key or value iterator, depending on flags. For a value
129  * iterator, performs value-lookup to convert the given list of jsids.
130  */
131 bool
132 EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
133
134 }
135
136 /*
137  * Convert the value stored in *vp to its iteration object. The flags should
138  * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
139  * for-in semantics are required, and when the caller can guarantee that the
140  * iterator will never be exposed to scripts.
141  */
142 extern JS_FRIEND_API(JSBool)
143 js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
144
145 extern JS_FRIEND_API(JSBool)
146 js_CloseIterator(JSContext *cx, JSObject *iterObj);
147
148 bool
149 js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id);
150
151 bool
152 js_SuppressDeletedIndexProperties(JSContext *cx, JSObject *obj, jsint begin, jsint end);
153
154 /*
155  * IteratorMore() indicates whether another value is available. It might
156  * internally call iterobj.next() and then cache the value until its
157  * picked up by IteratorNext(). The value is cached in the current context.
158  */
159 extern JSBool
160 js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval);
161
162 extern JSBool
163 js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval);
164
165 extern JSBool
166 js_ThrowStopIteration(JSContext *cx);
167
168 #if JS_HAS_GENERATORS
169
170 /*
171  * Generator state codes.
172  */
173 typedef enum JSGeneratorState {
174     JSGEN_NEWBORN,  /* not yet started */
175     JSGEN_OPEN,     /* started by a .next() or .send(undefined) call */
176     JSGEN_RUNNING,  /* currently executing via .next(), etc., call */
177     JSGEN_CLOSING,  /* close method is doing asynchronous return */
178     JSGEN_CLOSED    /* closed, cannot be started or closed again */
179 } JSGeneratorState;
180
181 struct JSGenerator {
182     JSObject            *obj;
183     JSGeneratorState    state;
184     JSFrameRegs         regs;
185     JSObject            *enumerators;
186     JSStackFrame        *floating;
187     js::Value           floatingStack[1];
188
189     JSStackFrame *floatingFrame() {
190         return floating;
191     }
192
193     JSStackFrame *liveFrame() {
194         JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
195                   (regs.fp != floatingFrame()));
196         return regs.fp;
197     }
198 };
199
200 extern JSObject *
201 js_NewGenerator(JSContext *cx);
202
203 /*
204  * Generator stack frames do not have stable pointers since they get copied to
205  * and from the generator object and the stack (see SendToGenerator). This is a
206  * problem for Block and With objects, which need to store a pointer to the
207  * enclosing stack frame. The solution is for Block and With objects to store
208  * a pointer to the "floating" stack frame stored in the generator object,
209  * since it is stable, and maintain, in the generator object, a pointer to the
210  * "live" stack frame (either a copy on the stack or the floating frame). Thus,
211  * Block and With objects must "normalize" to and from the floating/live frames
212  * in the case of generators using the following functions.
213  */
214 inline JSStackFrame *
215 js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
216 {
217     JS_ASSERT(cx->stack().contains(fp));
218     if (JS_UNLIKELY(fp->isGeneratorFrame()))
219         return cx->generatorFor(fp)->floatingFrame();
220     return fp;
221 }
222
223 /* Given a floating frame, given the JSGenerator containing it. */
224 extern JSGenerator *
225 js_FloatingFrameToGenerator(JSStackFrame *fp);
226
227 inline JSStackFrame *
228 js_LiveFrameIfGenerator(JSStackFrame *fp)
229 {
230     return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
231 }
232
233 #endif
234
235 extern js::Class js_GeneratorClass;
236 extern js::Class js_IteratorClass;
237 extern js::Class js_StopIterationClass;
238
239 static inline bool
240 js_ValueIsStopIteration(const js::Value &v)
241 {
242     return v.isObject() && v.toObject().getClass() == &js_StopIterationClass;
243 }
244
245 extern JSObject *
246 js_InitIteratorClasses(JSContext *cx, JSObject *obj);
247
248 #endif /* jsiter_h___ */