Reviewed by Darin and Geoff.
[WebKit-https.git] / JavaScriptCore / kjs / value.h
1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003-2005 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifndef KJS_VALUE_H
25 #define KJS_VALUE_H
26
27 #include "JSImmediate.h"
28 #include "collector.h"
29 #include "ustring.h"
30 #include <stddef.h> // for size_t
31
32 #ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
33
34 // Uncomment this to enable very verbose output from KJS
35 //#define KJS_VERBOSE
36 // Uncomment this to debug memory allocation and garbage collection
37 //#define KJS_DEBUG_MEM
38
39 #endif
40
41 namespace KJS {
42
43 class ExecState;
44 class JSObject;
45 class JSCell;
46
47 struct ClassInfo;
48
49 /**
50  * JSValue is the base type for all primitives (Undefined, Null, Boolean,
51  * String, Number) and objects in ECMAScript.
52  *
53  * Note: you should never inherit from JSValue as it is for primitive types
54  * only (all of which are provided internally by KJS). Instead, inherit from
55  * JSObject.
56  */
57 class JSValue {
58     friend class JSCell; // so it can derive from this class
59     friend class Collector; // so it can call downcast()
60
61 private:
62     JSValue();
63     virtual ~JSValue();
64
65 public:
66     // Querying the type.
67     JSType type() const;
68     bool isUndefined() const;
69     bool isNull() const;
70     bool isUndefinedOrNull() const;
71     bool isBoolean() const;
72     bool isNumber() const;
73     bool isString() const;
74     bool isObject() const;
75     bool isObject(const ClassInfo *) const;
76
77     // Extracting the value.
78     bool getBoolean(bool&) const;
79     bool getBoolean() const; // false if not a boolean
80     bool getNumber(double&) const;
81     double getNumber() const; // NaN if not a number
82     bool getString(UString&) const;
83     UString getString() const; // null string if not a string
84     JSObject *getObject(); // NULL if not an object
85     const JSObject *getObject() const; // NULL if not an object
86
87     // Extracting integer values.
88     bool getUInt32(uint32_t&) const;
89
90     // Basic conversions.
91     JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const;
92     bool toBoolean(ExecState *exec) const;
93     double toNumber(ExecState *exec) const;
94     UString toString(ExecState *exec) const;
95     JSObject *toObject(ExecState *exec) const;
96
97     // Integer conversions.
98     double toInteger(ExecState*) const;
99     int32_t toInt32(ExecState*) const;
100     int32_t toInt32(ExecState*, bool& ok) const;
101     uint32_t toUInt32(ExecState*) const;
102     uint32_t toUInt32(ExecState*, bool& ok) const;
103     uint16_t toUInt16(ExecState*) const;
104
105     // Garbage collection.
106     void mark();
107     bool marked() const;
108
109 private:
110     // Implementation details.
111     JSCell *downcast();
112     const JSCell *downcast() const;
113
114     // Give a compile time error if we try to copy one of these.
115     JSValue(const JSValue&);
116     JSValue& operator=(const JSValue&);
117 };
118
119 class JSCell : public JSValue {
120     friend class Collector;
121     friend class NumberImp;
122     friend class StringImp;
123     friend class JSObject;
124     friend class GetterSetterImp;
125 private:
126     JSCell();
127     virtual ~JSCell();
128 public:
129     // Querying the type.
130     virtual JSType type() const = 0;
131     bool isNumber() const;
132     bool isString() const;
133     bool isObject() const;
134     bool isObject(const ClassInfo *) const;
135
136     // Extracting the value.
137     bool getNumber(double&) const;
138     double getNumber() const; // NaN if not a number
139     bool getString(UString&) const;
140     UString getString() const; // null string if not a string
141     JSObject *getObject(); // NULL if not an object
142     const JSObject *getObject() const; // NULL if not an object
143
144     // Extracting integer values.
145     virtual bool getUInt32(uint32_t&) const;
146
147     // Basic conversions.
148     virtual JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const = 0;
149     virtual bool toBoolean(ExecState *exec) const = 0;
150     virtual double toNumber(ExecState *exec) const = 0;
151     virtual UString toString(ExecState *exec) const = 0;
152     virtual JSObject *toObject(ExecState *exec) const = 0;
153
154     // Garbage collection.
155     void *operator new(size_t);
156     virtual void mark();
157     bool marked() const;
158 };
159
160 JSValue *jsNumberCell(double);
161
162 JSCell *jsString(const UString &); // returns empty string if passed null string
163 JSCell *jsString(const char * = ""); // returns empty string if passed 0
164
165 extern const double NaN;
166 extern const double Inf;
167
168
169 inline JSValue *jsUndefined()
170 {
171     return JSImmediate::undefinedImmediate();
172 }
173
174 inline JSValue *jsNull()
175 {
176     return JSImmediate::nullImmediate();
177 }
178
179 inline JSValue *jsNaN()
180 {
181     return JSImmediate::NaNImmediate();
182 }
183
184 inline JSValue *jsBoolean(bool b)
185 {
186     return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
187 }
188
189 inline JSValue *jsNumber(double d)
190 {
191     JSValue *v = JSImmediate::fromDouble(d);
192     return v ? v : jsNumberCell(d);
193 }
194
195 inline JSValue::JSValue()
196 {
197 }
198
199 inline JSValue::~JSValue()
200 {
201 }
202
203 inline JSCell::JSCell()
204 {
205 }
206
207 inline JSCell::~JSCell()
208 {
209 }
210
211 inline bool JSCell::isNumber() const
212 {
213     return type() == NumberType;
214 }
215
216 inline bool JSCell::isString() const
217 {
218     return type() == StringType;
219 }
220
221 inline bool JSCell::isObject() const
222 {
223     return type() == ObjectType;
224 }
225
226 inline bool JSCell::marked() const
227 {
228     return Collector::isCellMarked(this);
229 }
230
231 inline void JSCell::mark()
232 {
233     return Collector::markCell(this);
234 }
235
236 inline JSCell *JSValue::downcast()
237 {
238     ASSERT(!JSImmediate::isImmediate(this));
239     return static_cast<JSCell *>(this);
240 }
241
242 inline const JSCell *JSValue::downcast() const
243 {
244     ASSERT(!JSImmediate::isImmediate(this));
245     return static_cast<const JSCell *>(this);
246 }
247
248 inline bool JSValue::isUndefined() const
249 {
250     return this == jsUndefined();
251 }
252
253 inline bool JSValue::isNull() const
254 {
255     return this == jsNull();
256 }
257
258 inline bool JSValue::isUndefinedOrNull() const
259 {
260     return JSImmediate::isUndefinedOrNull(this);
261 }
262
263 inline bool JSValue::isBoolean() const
264 {
265     return JSImmediate::isBoolean(this);
266 }
267
268 inline bool JSValue::isNumber() const
269 {
270     return JSImmediate::isNumber(this) || !JSImmediate::isImmediate(this) && downcast()->isNumber();
271 }
272
273 inline bool JSValue::isString() const
274 {
275     return !JSImmediate::isImmediate(this) && downcast()->isString();
276 }
277
278 inline bool JSValue::isObject() const
279 {
280     return !JSImmediate::isImmediate(this) && downcast()->isObject();
281 }
282
283 inline bool JSValue::getBoolean(bool& v) const
284 {
285     if (JSImmediate::isBoolean(this)) {
286         v = JSImmediate::toBoolean(this);
287         return true;
288     }
289     
290     return false;
291 }
292
293 inline bool JSValue::getBoolean() const
294 {
295     return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
296 }
297
298 inline bool JSValue::getNumber(double& v) const
299 {
300     if (JSImmediate::isImmediate(this)) {
301         v = JSImmediate::toDouble(this);
302         return true;
303     }
304     return downcast()->getNumber(v);
305 }
306
307 inline double JSValue::getNumber() const
308 {
309     return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : downcast()->getNumber();
310 }
311
312 inline bool JSValue::getString(UString& s) const
313 {
314     return !JSImmediate::isImmediate(this) && downcast()->getString(s);
315 }
316
317 inline UString JSValue::getString() const
318 {
319     return JSImmediate::isImmediate(this) ? UString() : downcast()->getString();
320 }
321
322 inline JSObject *JSValue::getObject()
323 {
324     return JSImmediate::isImmediate(this) ? 0 : downcast()->getObject();
325 }
326
327 inline const JSObject *JSValue::getObject() const
328 {
329     return JSImmediate::isImmediate(this) ? 0 : downcast()->getObject();
330 }
331
332 inline bool JSValue::getUInt32(uint32_t& v) const
333 {
334     if (JSImmediate::isImmediate(this)) {
335         double d = JSImmediate::toDouble(this);
336         if (!(d >= 0) || d > 0xFFFFFFFFUL) // true for NaN
337             return false;
338         v = static_cast<uint32_t>(d);
339         return JSImmediate::isNumber(this);
340     }
341     return downcast()->getUInt32(v);
342 }
343
344 inline void JSValue::mark()
345 {
346     ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
347     downcast()->mark();
348 }
349
350 inline bool JSValue::marked() const
351 {
352     return JSImmediate::isImmediate(this) || downcast()->marked();
353 }
354
355 inline JSType JSValue::type() const
356 {
357     return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : downcast()->type();
358 }
359
360 inline JSValue *JSValue::toPrimitive(ExecState *exec, JSType preferredType) const
361 {
362     return JSImmediate::isImmediate(this) ? const_cast<JSValue *>(this) : downcast()->toPrimitive(exec, preferredType);
363 }
364
365 inline bool JSValue::toBoolean(ExecState *exec) const
366 {
367     return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : downcast()->toBoolean(exec);
368 }
369
370 inline double JSValue::toNumber(ExecState *exec) const
371 {
372     return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : downcast()->toNumber(exec);
373 }
374
375 inline UString JSValue::toString(ExecState *exec) const
376 {
377     return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : downcast()->toString(exec);
378 }
379
380 inline JSObject* JSValue::toObject(ExecState* exec) const
381 {
382     return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : downcast()->toObject(exec);
383 }
384
385 } // namespace
386
387 #endif // KJS_VALUE_H